home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / migd / RCS / global.c,v < prev    next >
Encoding:
Text File  |  1992-06-17  |  140.7 KB  |  5,454 lines

  1. head     2.5;
  2. branch   ;
  3. access   ;
  4. symbols  before_fairness_changes:2.0 ckpt1:1.3;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 2.5
  10. date     92.06.16.20.51.54;  author jhh;  state Exp;
  11. branches ;
  12. next     2.4;
  13.  
  14. 2.4
  15. date     90.09.24.14.44.39;  author douglis;  state Exp;
  16. branches ;
  17. next     2.3;
  18.  
  19. 2.3
  20. date     90.09.14.14.05.45;  author douglis;  state Exp;
  21. branches ;
  22. next     2.2;
  23.  
  24. 2.2
  25. date     90.07.05.18.35.27;  author douglis;  state Exp;
  26. branches ;
  27. next     2.1;
  28.  
  29. 2.1
  30. date     90.07.05.13.19.25;  author douglis;  state Exp;
  31. branches ;
  32. next     2.0;
  33.  
  34. 2.0
  35. date     90.06.30.17.06.57;  author douglis;  state Stable;
  36. branches ;
  37. next     1.14;
  38.  
  39. 1.14
  40. date     90.06.30.17.06.07;  author douglis;  state Exp;
  41. branches ;
  42. next     1.13;
  43.  
  44. 1.13
  45. date     90.06.26.22.09.03;  author douglis;  state Exp;
  46. branches ;
  47. next     1.12;
  48.  
  49. 1.12
  50. date     90.05.28.17.06.38;  author douglis;  state Exp;
  51. branches ;
  52. next     1.11;
  53.  
  54. 1.11
  55. date     90.05.14.21.32.59;  author douglis;  state Exp;
  56. branches ;
  57. next     1.10;
  58.  
  59. 1.10
  60. date     90.05.03.11.17.32;  author douglis;  state Exp;
  61. branches ;
  62. next     1.9;
  63.  
  64. 1.9
  65. date     90.05.02.14.35.35;  author douglis;  state Exp;
  66. branches ;
  67. next     1.8;
  68.  
  69. 1.8
  70. date     90.05.02.12.30.46;  author douglis;  state Exp;
  71. branches ;
  72. next     1.7;
  73.  
  74. 1.7
  75. date     90.04.27.00.59.05;  author douglis;  state Exp;
  76. branches ;
  77. next     1.6;
  78.  
  79. 1.6
  80. date     90.04.24.18.00.32;  author douglis;  state Exp;
  81. branches ;
  82. next     1.5;
  83.  
  84. 1.5
  85. date     90.04.03.11.08.25;  author douglis;  state Exp;
  86. branches ;
  87. next     1.4;
  88.  
  89. 1.4
  90. date     90.03.14.12.49.38;  author douglis;  state Exp;
  91. branches ;
  92. next     1.3;
  93.  
  94. 1.3
  95. date     90.03.12.13.44.57;  author douglis;  state Exp;
  96. branches ;
  97. next     1.2;
  98.  
  99. 1.2
  100. date     90.02.28.10.45.36;  author douglis;  state Exp;
  101. branches ;
  102. next     1.1;
  103.  
  104. 1.1
  105. date     90.02.15.19.17.39;  author douglis;  state Exp;
  106. branches ;
  107. next     ;
  108.  
  109.  
  110. desc
  111. @Routines to manage the global loadavg data base.  
  112. @
  113.  
  114.  
  115. 2.5
  116. log
  117. @didn't call Host_End after Host_ByID
  118. @
  119. text
  120. @/* 
  121.  * global.c --
  122.  *
  123.  *    Routines to manage the global loadavg data base.  Only one
  124.  *    process is permitted to open the global pdev in master
  125.  *    mode and service requests on it.  All hosts run a daemon that
  126.  *    communicates periodically with the global server.  Clients
  127.  *    communicate with the global server to obtain load info and request
  128.  *    idle hosts.  Idle hosts may be released explicitly by ioctls with
  129.  *    the server, or implicitly upon closing the pdev connection.
  130.  *
  131.  *     The global server maintains an array of structures, one per host,
  132.  *    with the load information for each host.  The hosts are linked into
  133.  *    idle lists, which are distinguished by architecture type and
  134.  *    the type of processes running on the hosts. If a host is completely
  135.  *    idle, then it is available for any type of process.  On the other
  136.  *    hand, it might be used by a low priority process, and it could still
  137.  *    be used by a higher-priority process but not by another low priority
  138.  *    process.  In each case, the availability is determined by the
  139.  *    number of processors on the host, so a host with 4 processors and
  140.  *    three background jobs is presumed to be capable of a fourth background
  141.  *    job or up to 4 higher-priority jobs.  The queue for completely
  142.  *    idle hosts is sorted in order of idle time, but the other queues
  143.  *    are just FIFO since if a host already has stuff on it then it
  144.  *     is less likely to matter how long it's already been idle. (Maybe
  145.  *    this isn't true; in that case, sorting the other queues is
  146.  *    always possible.)
  147.  *
  148.  *    In addition, the server maintains information about each
  149.  *    process that is using idle hosts, and each user.  The per-user
  150.  *    information is not yet used but may be used to implement a fairness
  151.  *    policy at some future date.  The per-process information is associated
  152.  *    with the pdev handle for the client.  If the pdev is closed,
  153.  *    all hosts used by that process are marked available.
  154.  *
  155.  * Copyright 1989, 1990 Regents of the University of California
  156.  * Permission to use, copy, modify, and distribute this
  157.  * software and its documentation for any purpose and without
  158.  * fee is hereby granted, provided that the above copyright
  159.  * notice appear in all copies.  The University of California
  160.  * makes no representations about the suitability of this
  161.  * software for any purpose.  It is provided "as is" without
  162.  * express or implied warranty.
  163.  */
  164.  
  165. #ifndef lint
  166. static char rcsid[] = "$Header: /sprite/src/daemons/migd/RCS/global.c,v 2.4 90/09/24 14:44:39 douglis Exp $ SPRITE (Berkeley)";
  167. #endif /* not lint */
  168.  
  169.  
  170. #include <sprite.h>
  171. #include <string.h>
  172. #include <list.h>
  173. #include <errno.h>
  174. #include <status.h>
  175. #include "syslog.h"
  176. #include <bstring.h>
  177. #include <fs.h>
  178. #include <kernel/fs.h>
  179. #include <sys/types.h>
  180. #include <sys/time.h>
  181. #include <unistd.h>
  182. #include <stdlib.h>
  183. #include <stdio.h>
  184. #include <sys/dir.h>
  185. #include <sys/file.h>
  186. #include <sys/stat.h>
  187. #include <host.h>
  188. #include <signal.h>
  189. #include <pdev.h>
  190. #include <kernel/net.h>
  191. #include "mig.h"
  192. #include "migd.h"
  193. #include "migPdev.h"
  194.  
  195. /* 
  196.  * Define a structure for keeping track of info we need to send to
  197.  * clients.  Each message is a single int.
  198.  */
  199. typedef struct {
  200.     List_Links links;        /* Link to next message. */
  201.     int msg;            /* Integer-valued message to tell client. */
  202. } MessageBlock;
  203.  
  204. /* 
  205.  * A structure is used to keep track of outstanding requests,
  206.  * i.e., idle hosts that have been assigned to a process and not yet
  207.  * returned.   It points back to the open stream info and to two linked
  208.  * lists, one that's per stream and one that's per host.
  209.  */
  210. typedef struct RequestInfo {
  211.     List_Links  nextClientRequest;    /* Link to next request by same
  212.                        client. */
  213.     List_Links  nextHostRequest;    /* Link to next request for this
  214.                        host. */
  215.     List_Links  nextInUse;        /* Link to next request for this
  216.                        machine type and priority. */
  217.     int timestamp;            /* Time of request. */
  218.     int priority;            /* Priority of processes. */
  219.     int numProcessors;            /* Number of processors assigned. */
  220.     int idleTime;            /* Idle time of host at time of
  221.                        request (in case of eviction,
  222.                        for statistics). */
  223.     int flags;                /* Flags applied to request. */
  224.     union {
  225.     Migd_OpenStreamInfo *cltPtr;     /* Pointer back to open stream info
  226.                        for client. */
  227.     int processID;            /* ID of process, if agent. */
  228.     } client;
  229.     struct Migd_Info *migdPtr;        /* Pointer back to host assigned. */
  230. } RequestInfo;
  231.  
  232. #define NEXT_HOST_REQUEST_TO_INFO(listPtr) \
  233.     ( (RequestInfo *)((int)(listPtr) - sizeof(List_Links)) )
  234.  
  235. #define NEXT_HOST_IN_USE_TO_INFO(listPtr) \
  236.     ( (RequestInfo *)((int)(listPtr) - 2 * sizeof(List_Links)) )
  237.  
  238. /*
  239.  * Arguments to RevokePermission().  Indicates what to do with client and
  240.  * what to do with statistics gathering. 
  241.  */
  242. typedef enum {
  243.     REVOKE_EVICT,        /* Evicting processes. */
  244.     REVOKE_STOLEN,        /* Claiming for fairness purposes. */
  245.     REVOKE_IDLE,        /* Thought host was unused for a long time. */
  246. } RevokeAction;
  247.  
  248. /*
  249.  * Define the number of seconds we'll wait before notifying a process
  250.  * about new hosts being available if we just stole hosts from it.
  251.  */
  252. #define MIGD_STOLE_WINDOW 30
  253.  
  254.  
  255. static int maxArchTypes = MIG_MAX_ARCH_TYPES;      /* number of elements
  256.                            in arrays per-type */
  257. static char **archTypesArray;   /* array of strings mapping types to indexes
  258.                    in these arrays */
  259.  
  260. static int maxHosts = NET_NUM_SPRITE_HOSTS; /* number of hosts in arrays
  261.                            per-host */
  262. static int maxKnownHost = 0;    /* Highest known host ID. */
  263.  
  264. static Migd_Info **migInfoArray;    /* array of host info pointers */
  265. static List_Links *idleHostsArray[MIG_NUM_PRIORITIES];
  266.                     /* array of lists of idle hosts,
  267.                        indexed by type and priority. */
  268. static List_Links *inUseArray[MIG_NUM_PRIORITIES];
  269.                     /* array of lists of host requests,
  270.                        indexed by type and priority. */
  271. static List_Links *waitingLists[MIG_NUM_PRIORITIES];
  272.                     /* array of lists of waiting clients,
  273.                        indexed by type. */
  274.  
  275. static int hostsUp = 0;        /* Total number of hosts up, used for
  276.                    determining when it's safe to exit after
  277.                    termination. */
  278. static int hostCounts[MIG_MAX_ARCH_TYPES][MIG_NUM_STATES];
  279.                 /* Counts per-architecture, per-state. */
  280.  
  281. static int lastRequestHost = -1; /* ID of last host making a request. */
  282.  
  283. /*
  284.  * Global variables.
  285.  */
  286. int global_Debug = 0;        /* enable debugging info? */
  287.  
  288. int global_CheckpointInterval = MIG_TIMEOUT;    /* Interval for saving
  289.                            checkpoints. */
  290.  
  291. Mig_Stats global_Stats;        /* Statistics, maintained mostly by this
  292.                    file. */
  293.  
  294. #ifndef MIGD_CHECKPOINT_FILE
  295. #define MIGD_CHECKPOINT_FILE "/sprite/admin/migd/check"
  296. #endif /* MIGD_CHECKPOINT_FILE */
  297.  
  298. #ifndef MIGD_LOCK_FILE
  299. #define MIGD_LOCK_FILE "/sprite/admin/migd/lock"
  300. #endif /* MIGD_LOCK_FILE */
  301.  
  302. #ifndef MIGD_LOG_FILE
  303. #define MIGD_LOG_FILE "/sprite/admin/migd/log"
  304. #endif /* MIGD_LOG_FILE */
  305.  
  306. /* 
  307.  * Things to keep track of the files used (errors, and lock file).
  308.  */
  309. char *global_ErrorFile = NULL;    /* Place to write host-daemon errors,
  310.                    initialized in main. */
  311. static int  lockDesc;        /* Descriptor for lock file. */
  312. static struct stat descAtts;    /* Attributes of lock file. */
  313.  
  314. static void CreateMigdRecord();  /* Allocate a Migd_Info record. */
  315. static void RestoreCheckPoint(); /* Restore checkpoint from file. */
  316. static void SaveCheckPoint();      /* Save checkpoint to file. */
  317. static void CheckHostStatus();      /* Check the status of a host after an
  318.                     update. */
  319. static int  RemoveHost();      /* Remove host from list of hosts. */
  320. static int  HostIsIdle();      /* Check for host being idle. */
  321. static void InsertIdle();      /* Add host to list of idle hosts. */
  322. static void WakeupWaiters();      /* Wake up processes that want more hosts. */
  323. static void RecordEvictions();      /* Remove host from idle list and notify
  324.                     clients of evictions. */
  325. static void ForceHostIdle();      /* Make a host seem idle. */
  326. static void TellClient();      /* Notify a client about a change in
  327.                     status. */
  328. static int CheckFairness();      /* Check on host allocation fairness. */
  329. static void RevokePermission();     /* Notify a client that its permission to
  330.                     use a host has been revoked. */
  331. static Migd_Info *CltToMigd();     /* Map from client info to migd record. */
  332.  
  333. static void InitStats();    /* Initialize statistics. */
  334. static void DumpStats();    /* Dump statistics to file. */
  335. static int  ReadStats();    /* Read statistics from file. */
  336.  
  337.  
  338. /*
  339.  *----------------------------------------------------------------------
  340.  *
  341.  * Global_Init --
  342.  *
  343.  *    Initialize state of the global server.   Called when a process
  344.  *    forks and the child tries to become the master for the global
  345.  *    pdev.
  346.  *
  347.  * Results:
  348.  *    0 for successful completion, -1 for error, with errno indicating
  349.  *    the nature of the error.
  350.  *
  351.  * Side effects:
  352.  *    Opens pseudo-device, allocates arrays and assigns architecture strings
  353.  *    to indexes.
  354.  *
  355.  *----------------------------------------------------------------------
  356.  */
  357.  
  358. int
  359. Global_Init()
  360. {
  361.     Host_Entry *hostPtr;
  362.     int i, j;
  363.     Time    period;
  364.     char pidString[10];
  365.     FILE *logFile;
  366.  
  367.     migd_Pid = getpid();
  368.     
  369.     if (migd_LogToFiles) {
  370.     freopen(migd_GlobalErrorName, "a", stderr);
  371. #ifdef SEEK_REOPEN    
  372.     fseek(stderr, 0L, L_XTND);
  373. #endif /* SEEK_REOPEN */
  374.     if (fcntl(fileno(stderr), F_SETFL, FAPPEND) < 0) {
  375.         perror("fcntl");
  376.     }
  377.     }
  378.     
  379.     if (global_Debug > 0) {
  380.     int t = time(0);
  381.     fprintf(stderr, "Global_Init - process %x version %u on host %s:\n",
  382.         migd_Pid, migd_Version, migd_HostName);
  383.     fprintf(stderr, "\trun at %s", ctime(&t));
  384.     }
  385.  
  386.     /*
  387.      * We're trying to become the master for the global pdev.
  388.      */
  389.     migd_GlobalMaster = 1;
  390.  
  391.     /*
  392.      * Open pdev.  If someone else beats us to it, that's fine, let
  393.      * him handle it.
  394.      */
  395.     if (MigPdev_OpenMaster() < 0){
  396.     return(-1);
  397.     }
  398.  
  399.     /*
  400.      * Create a regular file that we use for detecting changes in master,
  401.      * since unlinking a pdev may cause the file descriptor to be reused
  402.      * prematurely.  If we can't create it, there's an error.  It may
  403.      * be that right after we unlink it, someone else creates it, in
  404.      * which case that process will become the global master.  The pdev
  405.      * is always opened successfully before the lock file is removed
  406.      * and rewritten.
  407.      */
  408.     (void) unlink(MIGD_LOCK_FILE);
  409.     lockDesc = open(MIGD_LOCK_FILE, O_WRONLY|O_CREAT|O_EXCL, 0644);
  410.     if (lockDesc < 0) {
  411.     perror("open (lock file)");
  412.     return(-1);
  413.     }
  414.     sprintf(pidString, "%x\n", migd_Pid);
  415.     if (write(lockDesc, pidString, strlen(pidString) + 1) !=
  416.     strlen(pidString) + 1) {
  417.     perror("write");
  418.     return(-1);
  419.     }
  420.     
  421.     if (fstat(lockDesc, &descAtts) < 0) {
  422.     SYSLOG1(LOG_ERR, "Exiting: unable to stat lock descriptor: %s.\n",
  423.            strerror(errno));
  424.     exit(1);
  425.     }
  426.  
  427.     /*
  428.      * Log a record saying we've started.  This is to a separate file from
  429.      * the usual error/debug log.
  430.      */
  431.     logFile = fopen(MIGD_LOG_FILE, "a");
  432.     if (logFile == (FILE *) NULL) {
  433.     fprintf(stderr, "Error opening %s: %s\n", MIGD_LOG_FILE, 
  434.         strerror(errno));
  435.     } else {
  436.     int t = time(0);
  437.     fprintf(logFile, "process %x version %u on host %s:\n",
  438.         migd_Pid, migd_Version, migd_HostName);
  439.     fprintf(logFile, "\trun at %s", ctime(&t));
  440.     fclose(logFile);
  441.     }
  442.     
  443.     /*
  444.      * We are the master.  Initialize the arrays of hosts and
  445.      * architecture types.
  446.      */
  447.     archTypesArray = (char **) Malloc(sizeof(char *) * maxArchTypes);
  448.     bzero((char *) archTypesArray, sizeof(char *) * maxArchTypes);
  449.  
  450.     migInfoArray = (Migd_Info **) Malloc(sizeof(Migd_Info *) *
  451.                     (maxHosts + 1));
  452.     bzero((char *) migInfoArray, sizeof(Migd_Info *) *
  453.       (maxHosts + 1));
  454.  
  455.     /*
  456.      * Go through the host database and set up an empty entry for
  457.      * each host.  Also, find all the architecture types to establish
  458.      * a mapping from host to type.
  459.      */
  460.     Host_Start();
  461.     while (1) {
  462.     hostPtr = Host_Next();
  463.     if (hostPtr == (Host_Entry *) NULL) {
  464.         break;
  465.     }
  466.     CreateMigdRecord(hostPtr);
  467.     }
  468.     Host_End();
  469.  
  470.     for (i = 0; i < MIG_NUM_PRIORITIES; i++) {
  471.     idleHostsArray[i] = (List_Links *) Malloc(maxArchTypes *
  472.                           sizeof(List_Links));
  473.     inUseArray[i] = (List_Links *) Malloc(maxArchTypes *
  474.                           sizeof(List_Links));
  475.     waitingLists[i] = (List_Links *) Malloc(maxArchTypes *
  476.                         sizeof(List_Links));
  477.     for (j = 0; j < maxArchTypes; j++) {
  478.         List_Init(&idleHostsArray[i][j]);
  479.         List_Init(&inUseArray[i][j]);
  480.         List_Init(&waitingLists[i][j]);
  481.     }
  482.     }
  483.  
  484.     /*
  485.      * Initialize statistics based on our own idea of the world.  This is
  486.      * used to ensure that things haven't changed (for example, the
  487.      * mapping of architecture types to id's).  
  488.      */
  489.     InitStats();
  490.  
  491.     
  492.     /*
  493.      * Find out the last time we heard from each host, in order to
  494.      * list downtimes for hosts that aren't currently up.  Get the stats
  495.      * saved by the last daemon.
  496.      */
  497.     RestoreCheckPoint();
  498.  
  499.     period.seconds = global_CheckpointInterval;
  500.     period.microseconds = 0;
  501.     Fs_TimeoutHandlerDestroy(migd_TimeoutToken);
  502.     migd_TimeoutToken = Fs_TimeoutHandlerCreate(period, TRUE, SaveCheckPoint,
  503.                         (ClientData) NULL);
  504.  
  505.     return (0);
  506. }
  507.  
  508.  
  509. /*
  510.  *----------------------------------------------------------------------
  511.  *
  512.  * InitStats --
  513.  *
  514.  *    Initialize structures relating to statistics.  This is called
  515.  *     at startup, if an error occurs reading the last checkpoint, or
  516.  *    via an ioctl.
  517.  *
  518.  * Results:
  519.  *    None.
  520.  *
  521.  * Side effects:
  522.  *    The statistics are zeroed, and a few fields are set.
  523.  *
  524.  *----------------------------------------------------------------------
  525.  */
  526.  
  527. static void
  528. InitStats()
  529. {
  530.     int i;
  531.     
  532.     bzero((char *) &global_Stats, sizeof(global_Stats));
  533.     global_Stats.version = migd_Version;
  534.     global_Stats.checkpointInterval = global_CheckpointInterval;
  535.     global_Stats.firstRun = time(0);
  536.     global_Stats.restarts = 1;
  537.     for (i = 0; i < maxArchTypes && i < MIG_MAX_ARCH_TYPES &&
  538.      archTypesArray[i] != (char *) NULL; i++) {
  539.     strncpy(global_Stats.archStats[i].arch, archTypesArray[i],
  540.         MIG_MAX_ARCH_LEN);
  541.     }
  542.     global_Stats.maxArchs = i;
  543.  
  544.     /*
  545.      * All other fields are zero.
  546.      */
  547. }
  548.  
  549. /*
  550.  *----------------------------------------------------------------------
  551.  *
  552.  * CreateMigdRecord --
  553.  *
  554.  *    Allocate and initialize a Migd_Info record given a Host_Entry
  555.  *    record.
  556.  *
  557.  * Results:
  558.  *    None.
  559.  *
  560.  * Side effects:
  561.  *    Allocates memory.  May create a new archType.  May increase
  562.  *    count of maximum known hostID.
  563.  *
  564.  *----------------------------------------------------------------------
  565.  */
  566.  
  567. static void
  568. CreateMigdRecord(hostPtr)
  569.     Host_Entry *hostPtr;
  570. {
  571.     int archType;
  572.     int host;
  573.     Migd_Info *migdPtr;
  574.     int i;
  575.     char *hp;
  576.     int nameLen;
  577.  
  578.     host = hostPtr->id;
  579.     if (host <= 0) {
  580.     SYSLOG1(LOG_ERR, "invalid host ID from Host_Next: %d.\n",
  581.            host);
  582.     return;
  583.     } else if (host > maxHosts) {
  584.     Migd_Info **newHostArray;
  585.  
  586.     /*
  587.      * Exceeded bounds of array.  Make it double the highest
  588.      * host known and continue.
  589.      */
  590.     SYSLOG2(LOG_WARNING,
  591.            "Host identifier (%d) exceeded maximum host ID (%d).  Need to recompile program\n.",
  592.            host,
  593.            maxHosts);
  594.     newHostArray = (Migd_Info **) Malloc(sizeof(Migd_Info *) *
  595.                          (host * 2 + 1));
  596.     bcopy((char *) migInfoArray, (char *) newHostArray,
  597.           sizeof(Migd_Info *) * (maxHosts + 1));
  598.     bzero((char *) &newHostArray[maxHosts], sizeof(Migd_Info *) *
  599.           (host  + 1));
  600.     free((char *) migInfoArray);
  601.     migInfoArray = newHostArray;
  602.     maxHosts = host * 2;
  603.     }
  604.         
  605.     for (i = 0; i < maxArchTypes; i++) {
  606.     if (archTypesArray[i] == (char *) NULL) {
  607.         archTypesArray[i] = Malloc(strlen(hostPtr->machType) + 1);
  608.         strcpy(archTypesArray[i], hostPtr->machType);
  609.         archType = i;
  610.         break;
  611.     }
  612.     if (strcmp(hostPtr->machType, archTypesArray[i]) == 0) {
  613.         archType = i;
  614.         break;
  615.     }
  616.     }
  617.     if (i == maxArchTypes) {
  618.     char **newArray;
  619.     /*
  620.      * Exceeded bounds of array.  Double its size and continue.
  621.      */
  622.     SYSLOG0(LOG_WARNING,
  623.            "Too many architecture types -- should recompile program\n.");
  624.     newArray = (char **) Malloc(sizeof(char *) * maxArchTypes * 2);
  625.     bcopy((char *) archTypesArray, (char *) newArray,
  626.           sizeof(char *) * maxArchTypes);
  627.     bzero((char *) &newArray[maxArchTypes], sizeof(char *) *
  628.           maxArchTypes);
  629.     free((char *) archTypesArray);
  630.     archTypesArray = newArray;
  631.     archTypesArray[maxArchTypes] =
  632.         Malloc(strlen(hostPtr->machType) + 1);
  633.     strcpy(archTypesArray[maxArchTypes], hostPtr->machType);
  634.     archType = maxArchTypes;
  635.     maxArchTypes *= 2;
  636.     }
  637.  
  638.     /*
  639.      * Allocate and initialize a record for this host.  We assume
  640.      * it is down until we hear from it.
  641.      */
  642.     migdPtr = mnew(Migd_Info);
  643.     bzero((char *) migdPtr, sizeof(Migd_Info));
  644.     migdPtr->archType = archType;
  645.     migdPtr->info.state = MIG_HOST_DOWN;
  646.     hostCounts[archType][MIG_HOST_DOWN]++;
  647.     migdPtr->info.hostID = host;
  648.     if (host > maxKnownHost) {
  649.     maxKnownHost = host;
  650.     }
  651.     migdPtr->lastHostAssigned = -1;
  652.     List_Init(&migdPtr->links);
  653.     List_Init(&migdPtr->clientList);
  654.  
  655.     for (hp = hostPtr->name, nameLen = 0; *hp != '\0' && *hp != '.'; hp++,
  656.      nameLen++) {
  657.     }
  658.     migdPtr->name = Malloc(nameLen + 1);
  659.     bcopy(hostPtr->name, migdPtr->name, nameLen);
  660.     migdPtr->name[nameLen] = '\0';
  661.  
  662.     migInfoArray[host] = migdPtr;
  663.     
  664. }
  665.  
  666.  
  667. /*
  668.  *----------------------------------------------------------------------
  669.  *
  670.  * Global_End --
  671.  *
  672.  *    Terminate service of the master end of the pdev.
  673.  *
  674.  * Results:
  675.  *    None.
  676.  *
  677.  * Side effects:
  678.  *    The pdev is removed and closed.
  679.  *
  680.  *----------------------------------------------------------------------
  681.  */
  682.  
  683. void
  684. Global_End()
  685. {
  686.     if (global_Debug > 0) {
  687.     PRINT_PID;
  688.     fprintf(stderr, "Global_End -\n");
  689.     }
  690.  
  691.     
  692.     
  693.     MigPdev_End();
  694.     if (global_Debug > 0) {
  695.     PRINT_PID;
  696.     fprintf(stderr, "Global_End - exiting.\n");
  697.     }
  698.     (void) unlink(MIGD_LOCK_FILE);
  699.     DATE();
  700.     exit(0);
  701.  
  702. }
  703.  
  704.  
  705. /*
  706.  *----------------------------------------------------------------------
  707.  *
  708.  * Global_Quit --
  709.  *
  710.  *    Called at exit.  If any outstanding daemons exist, it tells
  711.  *    them to quit as well.  This is normally done because of a
  712.  *    signal such as SIGINT (i.e., more for debugging than
  713.  *    production use).  Note, it uses the sprite signal numbering
  714.  *    scheme because it bypasses the compatibility library.  If
  715.  *    there are outstanding clients it doesn't actually exit itself;
  716.  *    instead the daemon waits until the last client exits (or
  717.  *    another signal occurs).
  718.  *
  719.  * Results:
  720.  *    None.
  721.  *
  722.  * Side effects:
  723.  *      Clients are signalled and should exit ASAP.
  724.  *
  725.  *----------------------------------------------------------------------
  726.  */
  727.  
  728. void
  729. Global_Quit()
  730. {
  731.     if (hostsUp == 0) {
  732.     Global_End();
  733.     } else {
  734.     MigPdev_SignalClients(SIG_TERM);
  735.     }
  736. }
  737.  
  738. /*
  739.  *----------------------------------------------------------------------
  740.  *
  741.  * Global_GetLoadInfo --
  742.  *
  743.  *    Get the information for one or more hosts and put it in a buffer.
  744.  *    This routine is called via a callback during an ioctl.  
  745.  *
  746.  * Results:
  747.  *    The size of the output buffer used is returned in *outBufSizePtr.
  748.  *    On error, a non-zero error status is returned.
  749.  *
  750.  * Side effects:
  751.  *    None.
  752.  *
  753.  *----------------------------------------------------------------------
  754.  */
  755.  
  756. /* ARGSUSED */
  757. int
  758. Global_GetLoadInfo(cltPtr, command, inBuffer, inBufSize, outBuffer,
  759.            outBufSizePtr)
  760.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  761.                    the request. */
  762.     int command;        /* Ignored. */
  763.     char *inBuffer;        /* Buffer to get arguments from. */
  764.     int inBufSize;        /* Size of the input buffer. */
  765.     char *outBuffer;        /* Buffer to place results. */
  766.     int *outBufSizePtr;        /* Size of the output buffer, modified with
  767.                    amount used. */
  768. {
  769.     Mig_InfoRequest *infoReqPtr;/* Request from client. */
  770.     int i;            /* Counter. */
  771.     int total;            /* Number of entries found. */
  772.     int firstHost;        /* Sprite ID of first host to return info
  773.                    for. */
  774.     int numRecs;        /* Maximum number of entries to return. */
  775.     char *bufPtr;        /* Pointer into output buffer. */
  776.     Mig_Info *infoPtr;        /* Pointer into output buffer. */
  777.     int *totalPtr;        /* Pointer into output buffer. */
  778.     
  779.     if (global_Debug > 2) {
  780.     PRINT_PID;
  781.     fprintf(stderr,
  782.            "Global_GetLoadInfo: called from process %x\n",
  783.            cltPtr->processID);
  784.     }
  785.     if (inBufSize != sizeof(Mig_InfoRequest)) {
  786.     if (global_Debug > 0) {
  787.         SYSLOG2(LOG_WARNING,
  788.            "Global_GetLoadInfo: bad input buffer size (%d) from process %x\n",
  789.            inBufSize, cltPtr->processID);
  790.     }
  791.     return(EINVAL);
  792.     }
  793.     global_Stats.getLoadRequests++;
  794.     infoReqPtr = (Mig_InfoRequest *) inBuffer;
  795.     firstHost = infoReqPtr->firstHost;
  796.     numRecs = infoReqPtr->numRecs;
  797.     if (firstHost <= 0 ||
  798.     *outBufSizePtr < (sizeof(int) + numRecs * sizeof(Mig_Info))) {
  799.     if (global_Debug > 0) {
  800.         SYSLOG2(LOG_WARNING,
  801.            "Global_GetLoadInfo: bad firstHost argument (%d) or output  buffer size (%d)\n",
  802.            firstHost,*outBufSizePtr);
  803.         SYSLOG2(LOG_WARNING,
  804.            "\tfor %d records, from process %x\n", numRecs,
  805.             cltPtr->processID);
  806.     }
  807.     return(EINVAL);
  808.     }
  809.  
  810.     if (global_Debug > 2) {
  811.     PRINT_PID;
  812.     fprintf(stderr,
  813.            "Global_GetLoadInfo: requested %d hosts starting at %d\n",
  814.            numRecs, firstHost);
  815.     }
  816.     bufPtr = outBuffer;
  817.     totalPtr = (int *) bufPtr;
  818.     bufPtr += 2 * sizeof(int);
  819.     infoPtr = (Mig_Info *) bufPtr;
  820.     for (i = firstHost, total = 0; i <= maxKnownHost && total < numRecs;
  821.      i++) { 
  822.     if (migInfoArray[i] != (Migd_Info *) NULL &&
  823.         migInfoArray[i]->info.loadVec.timestamp != 0) {
  824.         bcopy((char *) &migInfoArray[i]->info, (char *) infoPtr,
  825.           sizeof(Mig_Info));
  826.         infoPtr++;
  827.         total++;
  828.         if (global_Debug > 4) {
  829.         PRINT_PID;
  830.         fprintf(stderr,
  831.                "Global_GetLoadInfo: entry %d is %s\n",
  832.                total, migInfoArray[i]->name);
  833.         }
  834.     }
  835.     }
  836.     *totalPtr = total;
  837.     *outBufSizePtr = 2 * sizeof(int) + total * sizeof(Mig_Info);
  838.     if (global_Debug > 2) {
  839.     PRINT_PID;
  840.     fprintf(stderr,
  841.            "Global_GetLoadInfo: returning %d bytes for %d entries.\n",
  842.            *outBufSizePtr, total);
  843.     }
  844.     return(0);
  845.     
  846. }
  847.  
  848.  
  849. /*
  850.  *----------------------------------------------------------------------
  851.  *
  852.  * Global_GetIdle --
  853.  *
  854.  *    Get one or more idle hosts and put their IDs in a buffer.
  855.  *    This routine is called via a callback during an ioctl.  
  856.  *
  857.  * Results:
  858.  *    The size of the output buffer used is returned in *outBufSizePtr.
  859.  *    On error, a non-zero error status is returned.
  860.  *
  861.  * Side effects:
  862.  *    The hosts obtained may be shuffled to another queue.
  863.  *    Allocates various structures.
  864.  *
  865.  *----------------------------------------------------------------------
  866.  */
  867.  
  868. /* ARGSUSED */
  869. int
  870. Global_GetIdle(cltPtr, command, inBuffer, inBufSize, outBuffer,
  871.            outBufSizePtr)
  872.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  873.                    the request. */
  874.     int command;        /* Ignored. */
  875.     char *inBuffer;        /* Buffer to get arguments from. */
  876.     int inBufSize;        /* Size of the input buffer. */
  877.     char *outBuffer;        /* Buffer to place results. */
  878.     int *outBufSizePtr;        /* Size of the output buffer, modified with
  879.                    amount used. */
  880. {
  881.     Mig_IdleRequest *idleReqPtr;/* Request from client. */
  882.     int *outPtr;        /* Pointer into output buffer. */
  883.     int total;            /* Number of entries found. */
  884.     int numHosts;        /* Maximum number of host IDs to return. */
  885.     int priority;        /* Priority of process. */
  886.     int tryPrio;        /* Temporary variable for priority. */
  887.     List_Links *idleList;    /* Pointer to header of a list of idle
  888.                    hosts. */
  889.     List_Links *listPtr;    /* Current element in list. */
  890.     List_Links *nextPtr;    /* Next element in list. */
  891.     int    archType;        /* Numeric identifier for client
  892.                    architecture. */
  893.     int    migVersion;        /* Migration version of requester's host. */
  894.     Migd_Info *migdPtr;        /* Pointer to internal form of info for a
  895.                    host. */
  896.     Migd_Info *reqMigdPtr;    /* Pointer to info for requester's machine. */
  897.     Mig_Info *infoPtr;        /* Pointer to external form of info for
  898.                    host. */
  899.     RequestInfo *reqPtr;    /* Pointer to info for a request. */
  900.     Mig_ArchStats *archPtr;    /* For statistics. */
  901.     int retry;            /* Used for looping on requests. */
  902.  
  903.     if (inBufSize != sizeof(Mig_IdleRequest)) {
  904.     if (global_Debug > 0) {
  905.         SYSLOG2(LOG_WARNING,
  906.            "Global_GetIdle: bad input buffer size (%d) from process %x\n",
  907.            inBufSize, cltPtr->processID);
  908.     }
  909.     return(EINVAL);
  910.     }
  911.     idleReqPtr = (Mig_IdleRequest *) inBuffer;
  912.     numHosts = idleReqPtr->numHosts;
  913.  
  914.  
  915.     reqMigdPtr = migInfoArray[cltPtr->host];
  916.     if (reqMigdPtr == (Migd_Info *) NULL ||
  917.     reqMigdPtr->info.state == MIG_HOST_DOWN) {
  918.     if (global_Debug > 0) {
  919.         char buf[10];
  920.         SYSLOG1(LOG_WARNING,
  921.            "Global_GetIdle: no daemon for requester's host (%s).\n",
  922.             reqMigdPtr == (Migd_Info *) NULL ?
  923.             sprintf(buf, "%d", cltPtr->host) : reqMigdPtr->name);
  924.     }
  925.     return(ENOTCONN);
  926.     }
  927.     
  928.     if (global_Debug > 1) {
  929.     PRINT_PID;
  930.     fprintf(stderr,
  931.            "Global_GetIdle: request for %d hosts from process %x on %s\n",
  932.            numHosts, cltPtr->processID, reqMigdPtr->name);
  933.     }
  934.  
  935.     priority = idleReqPtr->priority;
  936.     if (numHosts <= 0 ||
  937.     *outBufSizePtr < (1 + numHosts) * sizeof(int) ||
  938.     priority < MIG_LOW_PRIORITY ||
  939.     priority > MIG_HIGH_PRIORITY) {
  940.     if (global_Debug > 0) {
  941.         PRINT_PID;
  942.         fprintf(stderr,
  943.            "Global_GetIdle: bad number of hosts requested (%d), priority (%d), or output buffer size (%d) from process %x\n",
  944.            numHosts, priority, *outBufSizePtr, cltPtr->processID);
  945.     }
  946.     return(EINVAL);
  947.     }
  948.  
  949.     archType = reqMigdPtr->archType;
  950.     migVersion = reqMigdPtr->info.migVersion;
  951.  
  952.     if (migd_DoStats) {
  953.     archPtr = &global_Stats.archStats[archType];
  954.     if (cltPtr->numRequested == 0) {
  955.         if (global_Debug > 2) {
  956.         PRINT_PID;
  957.         fprintf(stderr,
  958.                "Global_GetIdle: first request from process %x.\n",
  959.                cltPtr->processID);
  960.         }
  961.         archPtr->numClients++;
  962.     }
  963.     cltPtr->numRequested += numHosts;
  964.     if (cltPtr->numInUse + numHosts > cltPtr->maxRequests) {
  965.         cltPtr->maxRequests = cltPtr->numInUse + numHosts;
  966.     }
  967.     global_Stats.totalRequests += numHosts;
  968.     }
  969.  
  970.     /*
  971.      * Try to assign as many hosts as requested.  (At some point we
  972.      * might put in some sort of fairness constraints here.)  We
  973.      * look at hosts that are available for the given priority or lower,
  974.      * meaning that a normal priority job can run on a machine that's
  975.      * already being used for a background job but not vice-versa.
  976.      */
  977.  
  978.     outPtr = (int *) (outBuffer + sizeof(int));
  979.  
  980.     total = 0;
  981.     retry = 1;
  982.     while (retry) {
  983.  
  984.     tryPrio = MIG_LOW_PRIORITY;
  985.     while (total < numHosts && tryPrio <= priority) {
  986.         idleList = &idleHostsArray[tryPrio][archType];
  987.         nextPtr = List_First(idleList);
  988.         while (total < numHosts && !List_IsAtEnd(idleList, nextPtr)) {
  989.         listPtr = nextPtr;
  990.         nextPtr = List_Next(nextPtr);
  991.         migdPtr = (Migd_Info *) listPtr;
  992.         if (global_Debug > 3) {
  993.             PRINT_PID;
  994.             fprintf(stderr, "Examining %s.\n",
  995.                 migdPtr->name);
  996.         }
  997.         if (migdPtr->info.hostID == idleReqPtr->virtHost ||
  998.             migdPtr->info.hostID == cltPtr->host) {
  999.             if (global_Debug > 3) {
  1000.             PRINT_PID;
  1001.             fprintf(stderr, "Skipping over %s.\n",
  1002.                 migdPtr->name);
  1003.             }
  1004.             continue;
  1005.         }
  1006.         if (migdPtr->info.migVersion != migVersion) {
  1007.             if (global_Debug > 3) {
  1008.             PRINT_PID;
  1009.             fprintf(stderr,
  1010.                 "Migration version mismatch: %s version %d, %s version %d.\n",
  1011.                 migdPtr->name, migdPtr->info.migVersion,
  1012.                 reqMigdPtr->name, migVersion);
  1013.             }
  1014.             continue;
  1015.         }
  1016.         infoPtr = (Mig_Info *) &migdPtr->info;
  1017.         infoPtr->foreign[priority]++;
  1018.         if (infoPtr->foreign[priority] >= infoPtr->maxProcs) {
  1019.             /*
  1020.              * Used up all the processors on this host for processes
  1021.              * of this type, so put the host on the queue for
  1022.              * the next higher priority.
  1023.              */
  1024.             List_Remove(listPtr);
  1025.             hostCounts[archType][infoPtr->state]--;
  1026.             if (priority < MIG_HIGH_PRIORITY) {
  1027.             List_Insert(listPtr,
  1028.                     LIST_ATREAR(&idleHostsArray
  1029.                         [priority + 1][archType]));
  1030.             infoPtr->state = MIG_HOST_PART_USED;
  1031.             } else {
  1032.             infoPtr->state = MIG_HOST_FULL;
  1033.             }
  1034.             hostCounts[archType][infoPtr->state]++;
  1035.         }
  1036.         /*
  1037.          * Allocate a new request info structure and set it up
  1038.          * so we can find this request via the host's record or via the
  1039.          * client process.  Only chain it to the client process if
  1040.          * it isn't an "agent" request, since we reclaim hosts on the
  1041.          * client's chain of requests when the connection is closed.
  1042.          *
  1043.          * XXX We'd like to assign multiple processors in a single shot
  1044.          * here...
  1045.          */
  1046.         reqPtr = mnew(RequestInfo);
  1047.         reqPtr->priority = priority;
  1048.         reqPtr->migdPtr = migdPtr;
  1049.         reqPtr->flags = idleReqPtr->flags;
  1050.         reqPtr->idleTime = migdPtr->info.loadVec.noInput;
  1051.         reqPtr->numProcessors = 1;
  1052.         if (! (reqPtr->flags & MIG_PROC_AGENT)) {
  1053.             reqPtr->client.cltPtr = cltPtr;
  1054.             List_InitElement(&reqPtr->nextClientRequest);
  1055.             List_Insert(&reqPtr->nextClientRequest,
  1056.                 LIST_ATREAR(&cltPtr->currentRequests));
  1057.         } else {
  1058.             reqPtr->client.processID = cltPtr->processID;
  1059.             migdPtr->flags |= MIGD_CHECK_COUNT;
  1060.         }
  1061.         migdPtr->flags &= ~MIGD_WAS_EMPTY;
  1062.         if (migd_DoStats) {
  1063.             int noInput;
  1064.  
  1065.             global_Stats.totalObtained++;
  1066.             noInput = (infoPtr->loadVec.noInput + 30) / 60 ;
  1067.             reqPtr->timestamp = time(0);
  1068.             reqPtr->idleTime = noInput;
  1069.             ADD_WITH_OVERFLOW(archPtr->counters.hostIdleObtained, noInput);
  1070.             ADD_WITH_OVERFLOW(archPtr->squared.hostIdleObtained,
  1071.                       noInput * noInput);
  1072.             /*
  1073.              * Is this host being assigned to the last host that was
  1074.              * using it?
  1075.              */
  1076.             if (migdPtr->lastHostAssigned == cltPtr->host) {
  1077.             if (global_Debug > 4) {
  1078.                 PRINT_PID;
  1079.                 fprintf(stderr, "\t** Repeat assignment:\n");
  1080.             }
  1081.             global_Stats.numRepeatAssignments++;
  1082.             } else if (migdPtr->lastHostAssigned == -1) {
  1083.             if (global_Debug > 4) {
  1084.                 PRINT_PID;
  1085.                 fprintf(stderr, "\t** First assignment to host:\n");
  1086.             }
  1087.             global_Stats.numFirstAssignments++;
  1088.             }
  1089.             migdPtr->lastHostAssigned = cltPtr->host;
  1090.  
  1091.             if (cltPtr->host == lastRequestHost) {
  1092.             if (global_Debug > 4) {
  1093.                 PRINT_PID;
  1094.                 fprintf(stderr, "\t** Repeat requesting host:\n");
  1095.             }
  1096.             global_Stats.numRepeatRequests++;
  1097.             }
  1098.             lastRequestHost = cltPtr->host;
  1099.         }
  1100.  
  1101.         List_InitElement(&reqPtr->nextHostRequest);
  1102.         List_Insert(&reqPtr->nextHostRequest,
  1103.                 LIST_ATREAR(&migdPtr->clientList));
  1104.  
  1105.         List_InitElement(&reqPtr->nextInUse);
  1106.         List_Insert(&reqPtr->nextInUse,
  1107.                 LIST_ATREAR(&inUseArray[priority + 1][archType]));
  1108.         
  1109.         if (global_Debug > 2) {
  1110.             PRINT_PID;
  1111.             fprintf(stderr, "\t** Assigning %s to process %x.\n",
  1112.                 migdPtr->name, cltPtr->processID);
  1113.         }
  1114.         total++;
  1115.         *outPtr = infoPtr->hostID;
  1116.         outPtr++;
  1117.         }
  1118.         tryPrio++;
  1119.     }
  1120.     if (total < numHosts) {
  1121.         retry = CheckFairness(cltPtr, priority);
  1122.     } else {
  1123.         retry = 0;
  1124.     }
  1125.  
  1126.     }
  1127.     if (global_Debug > 1) {
  1128.     PRINT_PID;
  1129.     fprintf(stderr, "Global_GetIdle: allocated %d hosts to process %x\n",
  1130.            total, cltPtr->processID);
  1131.     }
  1132.  
  1133.     outPtr = (int *) outBuffer;
  1134.     *outPtr = total;
  1135.     *outBufSizePtr = (total + 1) * sizeof(int);
  1136.  
  1137.     cltPtr->numInUse += total;
  1138.     if (migd_DoStats) {
  1139.     cltPtr->numObtained += total;
  1140.     if (cltPtr->numInUse > cltPtr->maxObtained) {
  1141.         cltPtr->maxObtained = cltPtr->numInUse;
  1142.     }
  1143.     }
  1144.     
  1145.     if (total < numHosts && cltPtr->waitPtr == (Migd_WaitList *) NULL) {
  1146.     List_Links *waitingList = &waitingLists[priority][archType];
  1147.     Migd_WaitList *waitPtr = mnew(Migd_WaitList);
  1148.  
  1149.     if (global_Debug > 2) {
  1150.         PRINT_PID;
  1151.         fprintf(stderr, "\t** Process %x put on waiting list.\n",
  1152.            cltPtr->processID);
  1153.     }
  1154.     List_InitElement(&waitPtr->links);
  1155.     waitPtr->cltPtr = cltPtr;
  1156.     cltPtr->waitPtr = waitPtr;
  1157.     List_Insert(&waitPtr->links, LIST_ATREAR(waitingList));
  1158.     cltPtr->denied = 1;
  1159.     }
  1160.  
  1161.  
  1162.     return(0);
  1163.     
  1164. }
  1165.  
  1166.  
  1167. /*
  1168.  *----------------------------------------------------------------------
  1169.  *
  1170.  * CheckFairness --
  1171.  *
  1172.  *    Check on how hosts are allocated to see if hosts should be
  1173.  *    reclaimed.
  1174.  *
  1175.  * Results:
  1176.  *    Returns 1 if more hosts are available, or 0 if not.
  1177.  *
  1178.  * Side effects:
  1179.  *    May send message to migration daemons to ask them to evict.
  1180.  *    Flags the owner of the processes that we kick off so that
  1181.  *    that process won't be assigned hosts anytime soon if there
  1182.  *    are other processes that want hosts.
  1183.  *
  1184.  *----------------------------------------------------------------------
  1185.  */
  1186.  
  1187. static int
  1188. CheckFairness(cltPtr, priority)
  1189.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  1190.                    the request. */
  1191.     int priority;        /* Priority of process allocated. */
  1192. {
  1193.     RequestInfo *reqPtr;
  1194.     Migd_Info *cltMigdPtr;    /* Pointer to info for requesting client's
  1195.                    machine. */
  1196.     Migd_Info *migdPtr;        /* Pointer to info for various other
  1197.                    machines. */
  1198.     int    migVersion;        /* Migration version of requester's host. */
  1199.     Migd_OpenStreamInfo *reqCltPtr; /* Client that made request we're looking
  1200.                        at. */
  1201.     RequestInfo *bestReqPtr = NULL; /* Best host we've seen so far. */
  1202.     Migd_OpenStreamInfo *bestCltPtr; /* Client using that host with this
  1203.                     priority. */
  1204.     List_Links *listPtr;    /* Pointer to chain through list. */
  1205.     int okayToUse;        /* Flag while stepping through loop. */
  1206.     int checkPrio;        /* Priority index in loop. */
  1207.  
  1208.  
  1209.     if (global_Debug > 2) {
  1210.     PRINT_PID;
  1211.     fprintf(stderr,
  1212.            "CheckFairness called: client %x priority %d.\n",
  1213.        cltPtr->processID, priority);
  1214.     }
  1215.     
  1216.  
  1217.  
  1218.     cltMigdPtr = migInfoArray[cltPtr->host];
  1219.     migVersion = cltMigdPtr->info.migVersion;
  1220.  
  1221.     /*
  1222.      * Initialize bestCltPtr to ourselves so we only look at clients
  1223.      * with more hosts in use than we have.  We also fudge our count
  1224.      * to ensure that we don't steal from someone with 2 hosts to give a
  1225.      * host to someone with one host.  
  1226.      */
  1227.     bestCltPtr = cltPtr;
  1228.     cltPtr->numInUse++;
  1229.     
  1230.     LIST_FORALL(&inUseArray[priority + 1][cltMigdPtr->archType], listPtr) {
  1231.     reqPtr = NEXT_HOST_IN_USE_TO_INFO(listPtr);
  1232.     if (reqPtr->flags & (MIG_PROC_AGENT)) {
  1233.         if (global_Debug > 3) {
  1234.         PRINT_PID;
  1235.         fprintf(stderr,
  1236.                "CheckFairness skipping request on host %d, flags 0x%x.\n",
  1237.             reqPtr->migdPtr->info.hostID, reqPtr->flags);
  1238.         }
  1239.         continue;
  1240.     }
  1241.     reqCltPtr = reqPtr->client.cltPtr;
  1242.     migdPtr = migInfoArray[reqCltPtr->host];
  1243.     if (migdPtr->info.migVersion != migVersion) {
  1244.         if (global_Debug > 3) {
  1245.         PRINT_PID;
  1246.         fprintf(stderr,
  1247.                "CheckFairness skipping request on host %d, migration version %d.\n",
  1248.             reqPtr->migdPtr->info.hostID, migdPtr->info.migVersion);
  1249.         }
  1250.         continue;
  1251.     }
  1252.     /*
  1253.      * We want to see if the host that was already is assigned is the
  1254.      * same as the host making the new request, in which case there's
  1255.      * no point in reclaiming it since the new requester won't use it.
  1256.      */
  1257.     if (reqPtr->migdPtr->info.hostID == cltPtr->host) {
  1258.         if (global_Debug > 3) {
  1259.         PRINT_PID;
  1260.         fprintf(stderr,
  1261.                "CheckFairness skipping request using host %d assigned to process %x: same host as new requester.\n",
  1262.             reqPtr->migdPtr->info.hostID, reqCltPtr->processID);
  1263.         }
  1264.         continue;
  1265.     }
  1266.     /*
  1267.      * Only reclaim a host if it's assigned to only one process, at
  1268.      * least for now.  Otherwise it will evict a process and we'll
  1269.      * never notify the process's agent.  We check for a count of 1
  1270.      * at the priority we're evicting and 0 elsewhere.
  1271.      */
  1272.     for (okayToUse = 1, checkPrio = MIG_LOW_PRIORITY;
  1273.          okayToUse && checkPrio <= MIG_HIGH_PRIORITY;
  1274.          checkPrio++) {
  1275.         if (reqPtr->migdPtr->info.foreign[checkPrio] >
  1276.         ((priority == checkPrio) ? 1 : 0)) {
  1277.         if (global_Debug > 1) {
  1278.             PRINT_PID;
  1279.             fprintf(stderr,
  1280.                 "CheckFairness skipping request using host %d because more than one client assigned to this host.\n",
  1281.                 reqPtr->migdPtr->info.hostID);
  1282.         }
  1283.         okayToUse = 0;
  1284.         }
  1285.     }
  1286.     if (!okayToUse) {
  1287.         continue;
  1288.     }
  1289.     if (global_Debug > 5) {
  1290.         PRINT_PID;
  1291.         fprintf(stderr,
  1292.            "CheckFairness comparing client %x (%d hosts) to client %x (%d hosts).\n",
  1293.             reqCltPtr->processID, reqCltPtr->numInUse,
  1294.             bestCltPtr->processID, bestCltPtr->numInUse);
  1295.     }
  1296.     if (reqCltPtr->numInUse > bestCltPtr->numInUse) {
  1297.         if (global_Debug > 4) {
  1298.         PRINT_PID;
  1299.         fprintf(stderr,
  1300.                "CheckFairness choosing client %x using %d hosts, this one %d.\n",
  1301.            reqCltPtr->processID, reqCltPtr->numInUse,
  1302.             bestCltPtr->numInUse);
  1303.         }
  1304.         bestCltPtr = reqCltPtr;
  1305.         bestReqPtr = reqPtr;
  1306.     } else if (reqCltPtr == bestCltPtr) {
  1307.         bestReqPtr = reqPtr;
  1308.         if (global_Debug > 4) {
  1309.         PRINT_PID;
  1310.         fprintf(stderr,
  1311.                "CheckFairness changing to evict client %x on host %d.\n",
  1312.            reqCltPtr->processID, reqPtr->migdPtr->info.hostID);
  1313.         }
  1314.     }
  1315.     }
  1316.     /*
  1317.      * Undo the fudge factor.
  1318.      */
  1319.     cltPtr->numInUse--;
  1320.     if (bestCltPtr != cltPtr) {
  1321.     if (global_Debug > 1) {
  1322.         PRINT_PID;
  1323.         fprintf(stderr,
  1324.            "CheckFairness evicting processes on host %s.\n",
  1325.             bestReqPtr->migdPtr->name);
  1326.     }
  1327.     TellClient(bestReqPtr->migdPtr->cltPtr, 0);
  1328.     RevokePermission(bestReqPtr, REVOKE_STOLEN);
  1329.     List_Remove(&bestReqPtr->nextHostRequest);
  1330.     if (HostIsIdle(bestReqPtr->migdPtr)) {
  1331.         List_Remove((List_Links *) bestReqPtr->migdPtr);
  1332.     }
  1333.     InsertIdle(bestReqPtr->migdPtr);
  1334.     free(bestReqPtr);
  1335.     return(1);
  1336.     }
  1337.     return(0);
  1338. }
  1339.  
  1340.  
  1341. /*
  1342.  *----------------------------------------------------------------------
  1343.  *
  1344.  * Global_DoneIoctl --
  1345.  *
  1346.  *    Note that a process is through with one or more hosts.
  1347.  *    This routine is called via a callback during an ioctl.
  1348.  *    It's really just a stub to call a regular routine without
  1349.  *     the extra args.
  1350.  *
  1351.  * Results:
  1352.  *    On error, a non-zero error status is returned, else 0.
  1353.  *
  1354.  * Side effects:
  1355.  *    The hosts are put back on appropriate queues.
  1356.  *
  1357.  *----------------------------------------------------------------------
  1358.  */
  1359.  
  1360. /* ARGSUSED */
  1361. int
  1362. Global_DoneIoctl(cltPtr, command, inBuffer, inBufSize, outBuffer,
  1363.            outBufSizePtr)
  1364.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  1365.                    the request. */
  1366.     int command;        /* Ignored. */
  1367.     char *inBuffer;        /* Buffer to get arguments from. */
  1368.     int inBufSize;        /* Size of the input buffer. */
  1369.     char *outBuffer;        /* Buffer to place results, not used. */
  1370.     int *outBufSizePtr;        /* Size of the output buffer, set to 0. */
  1371. {
  1372.     int *hostPtr;        /* Pointer into input buffer. */
  1373.     int i;            /* Counter. */
  1374.     int numArgs;        /* Number of args (host IDs). */
  1375.     int status;            /* Status from subroutine calls. */
  1376.  
  1377.     if ((inBufSize % sizeof(int)) != 0 || inBufSize <= 0) {
  1378.     if (global_Debug > 0) {
  1379.         SYSLOG2(LOG_WARNING,
  1380.            "Global_DoneIoctl: bad input buffer size (%d) from process %x\n",
  1381.            inBufSize, cltPtr->processID);
  1382.     }
  1383.     return(EINVAL);
  1384.     }
  1385.     numArgs = inBufSize / sizeof(int);
  1386.     hostPtr = (int *) inBuffer;
  1387.     for (i = 0; i < numArgs; i++, hostPtr++) {
  1388.     status = Global_Done(cltPtr, *hostPtr, 0);
  1389.     if (status != 0) {
  1390.         return(status);
  1391.     }
  1392.     }
  1393.     return(0);
  1394. }
  1395.  
  1396.  
  1397.  
  1398. /*
  1399.  *----------------------------------------------------------------------
  1400.  *
  1401.  * Global_Done --
  1402.  *
  1403.  *    Note that a process is through with one or more hosts.
  1404.  *    Takes a single host specification, which may be MIG_ALL_HOSTS
  1405.  *    to indicate that all hosts are to be returned.
  1406.  *
  1407.  * Results:
  1408.  *    Returns 0.
  1409.  *
  1410.  * Side effects:
  1411.  *    The hosts may be moved to a different queue.  Memory is freed.
  1412.  *
  1413.  *----------------------------------------------------------------------
  1414.  */
  1415.  
  1416. int
  1417. Global_Done(cltPtr, host, exiting)
  1418.     Migd_OpenStreamInfo *cltPtr;/* Information about the client involved. */
  1419.     int host;            /* Host specification. */
  1420.     int exiting;        /* Whether this call is because the process
  1421.                    is exiting. */
  1422. {
  1423.     int priority;        /* Priority of process. */
  1424.     List_Links *cltList;    /* Pointer to header of client's list of
  1425.                    hosts it's using. */
  1426.     List_Links *cltListPtr;    /* Pointer into list. */
  1427.     List_Links *listPtr;    /* Temporary var: pointer to element of list. */
  1428.     List_Links *nextPtr;    /* For iterations, pointer to next element
  1429.                    of list. */
  1430.     int numReturned = 0;    /* Number of hosts returned. */
  1431.     Migd_Info *migdPtr;        /* Pointer to internal form of info for
  1432.                    a host. */
  1433.     Mig_Info *infoPtr;        /* Pointer to external form of info for
  1434.                    host. */
  1435.     RequestInfo *reqPtr;    /* Pointer to info for a request. */
  1436.     MessageBlock *msgPtr;    /* Pointer to message enqueued for client. */
  1437.     int returnCode = 0;        /* Value to return at end. */
  1438.     int requests;        /* Number of hosts requested, for statistics. */
  1439.     int obtained;        /* Number of hosts obtained, for statistics. */
  1440.     Mig_ArchStats *archStatsPtr;/* Pointer to per-architecture statistics. */
  1441.  
  1442.     
  1443.     if (global_Debug > 2) {
  1444.     if (host) {
  1445.         PRINT_PID;
  1446.         fprintf(stderr,
  1447.            "Global_Done: return %s to free pool for process %x\n",
  1448.            migInfoArray[host]->name, cltPtr->processID);
  1449.     } else {
  1450.         PRINT_PID;
  1451.         fprintf(stderr,
  1452.            "Global_Done: return all hosts to free pool for process %x\n",
  1453.            cltPtr->processID);
  1454.     }
  1455.     }
  1456.  
  1457.     /*
  1458.      * Check the list of hosts this client is using.
  1459.      */
  1460.  
  1461.     
  1462.     cltList = &cltPtr->currentRequests;
  1463.     if (List_IsEmpty(cltList)) {
  1464.     if (global_Debug > 2) {
  1465.         PRINT_PID;
  1466.         fprintf(stderr,
  1467.            "Global_Done: process %x has empty client list\n",
  1468.            cltPtr->processID);
  1469.     }
  1470.     goto done;
  1471.     }
  1472.     
  1473.  
  1474.     
  1475.     cltListPtr = List_First(cltList);
  1476.  
  1477.     /*
  1478.      * Go through list of requests looking for this host, or for each
  1479.      * host if so specified.
  1480.      */
  1481.  
  1482.     while (!List_IsAtEnd(cltList, cltListPtr)) {
  1483.  
  1484.     reqPtr = (RequestInfo *) cltListPtr;
  1485.     migdPtr = reqPtr->migdPtr;
  1486.     infoPtr = &migdPtr->info;
  1487.     priority  = reqPtr->priority;
  1488.     if (host != MIG_ALL_HOSTS && infoPtr->hostID != host) {
  1489.         cltListPtr = List_Next(cltListPtr);
  1490.         continue;
  1491.     }
  1492.     /*
  1493.      * Found a record for a host assignment we want to remove.
  1494.      * First extract it from the client's list and from the list
  1495.      * associated with the host being used.
  1496.      */
  1497.     listPtr = List_Next(cltListPtr);
  1498.     List_Remove(cltListPtr);
  1499.     cltListPtr = listPtr;
  1500.     listPtr = &reqPtr->nextHostRequest;
  1501.     List_Remove(listPtr);
  1502.     listPtr = &reqPtr->nextInUse;
  1503.     List_Remove(listPtr);
  1504.     numReturned++;
  1505.  
  1506.     infoPtr->foreign[priority] -= reqPtr->numProcessors;
  1507.     if (infoPtr->foreign[priority] == infoPtr->maxProcs - 1) {
  1508.         /*
  1509.          * Now have a free processor on this host for processes
  1510.          * of this type, so put the host on the queue for
  1511.          * this priority.
  1512.          */
  1513.         if (HostIsIdle(migdPtr)) {
  1514.         List_Remove((List_Links *) migdPtr);
  1515.         }
  1516.         if (infoPtr->loadVec.allowMigration) {
  1517.         InsertIdle(migdPtr);
  1518.         } else {
  1519.         migdPtr->info.state = MIG_HOST_ACTIVE;
  1520.         }
  1521.     } else if (global_Debug > 1) {
  1522.         PRINT_PID;
  1523.         fprintf(stderr,
  1524.            "Foreign count %d of priority %d on %s not just below maxProcs (%d).\n",
  1525.            infoPtr->foreign[priority], priority, migdPtr->name,
  1526.            infoPtr->maxProcs);
  1527.     }
  1528.     if (migd_DoStats) {
  1529.         int curTime = time(0);
  1530.         int timeUsed = curTime - reqPtr->timestamp;
  1531.         global_Stats.archStats[migdPtr->archType].counters.timeUsed +=
  1532.         timeUsed;
  1533.         global_Stats.archStats[migdPtr->archType].squared.timeUsed +=
  1534.         timeUsed * timeUsed;
  1535.     }
  1536.     
  1537.     free ((char *) reqPtr);
  1538.     }
  1539.  
  1540.     done:
  1541.     if (exiting) {
  1542.     /*
  1543.      * Clean up after the process -- get rid of messages, and the message
  1544.      * list.  Record statistics.
  1545.      */
  1546.     listPtr = List_First(&cltPtr->messages);
  1547.     while (!List_IsAtEnd(&cltPtr->messages, listPtr)) {
  1548.         nextPtr = List_Next(listPtr);
  1549.         msgPtr = (MessageBlock *) listPtr;
  1550.         if (msgPtr->msg == host || host == MIG_ALL_HOSTS) {
  1551.         List_Remove(listPtr);
  1552.         free((char *) listPtr);
  1553.         }
  1554.         listPtr = nextPtr;
  1555.     }
  1556.     if (List_IsEmpty(&cltPtr->messages)) {
  1557.         cltPtr->defaultSelBits &= ~FS_READ;
  1558.     }
  1559.  
  1560.     if (cltPtr->waitPtr != (Migd_WaitList *) NULL) {
  1561.         List_Remove((List_Links *) cltPtr->waitPtr);
  1562.         free((char *) cltPtr->waitPtr);
  1563.         cltPtr->waitPtr = (Migd_WaitList *) NULL;
  1564.     }
  1565.  
  1566.     /*
  1567.      * Manage statistics.  We only count processes that have ever
  1568.      * requested hosts, and only when they close their pdev.
  1569.      */
  1570.     if (migd_DoStats && cltPtr->numRequested > 0) {
  1571.         archStatsPtr = &global_Stats.archStats
  1572.         [migInfoArray[cltPtr->host]->archType];
  1573. #ifndef min
  1574. #define min(a, b) (((a) < (b)) ? (a) : (b))
  1575. #endif
  1576.         requests = min(cltPtr->maxRequests, MIG_MAX_HOSTS_DIST);
  1577.         obtained = min(cltPtr->maxObtained, MIG_MAX_HOSTS_DIST);
  1578.         if (global_Debug > 3) {
  1579.         PRINT_PID;
  1580.         fprintf(stderr,
  1581.             "Global_Done: process %x had a max of %d requests, %d obtained, %d stolen.\n",
  1582.             cltPtr->processID, requests, obtained,
  1583.             cltPtr->numStolen);
  1584.         }
  1585.         if (cltPtr->denied == 0) {
  1586.         archStatsPtr->gotAll++;
  1587.         }
  1588.         archStatsPtr->requestDist[requests]++;
  1589.         archStatsPtr->obtainedDist[obtained]++;
  1590.         archStatsPtr->counters.requested += cltPtr->numRequested;
  1591.         archStatsPtr->squared.requested +=
  1592.         cltPtr->numRequested * cltPtr->numRequested;
  1593.         archStatsPtr->counters.obtained += cltPtr->numObtained;
  1594.         archStatsPtr->squared.obtained +=
  1595.         cltPtr->numObtained * cltPtr->numObtained;
  1596.         archStatsPtr->counters.evicted += cltPtr->numEvicted;
  1597.         archStatsPtr->squared.evicted +=
  1598.         cltPtr->numEvicted * cltPtr->numEvicted;
  1599.         archStatsPtr->counters.reclaimed += cltPtr->numStolen;
  1600.         archStatsPtr->squared.reclaimed +=
  1601.         cltPtr->numStolen * cltPtr->numStolen;
  1602.     }
  1603.     }
  1604.     
  1605.     if (global_Debug > 2) {
  1606.     PRINT_PID;
  1607.     fprintf(stderr, "Global_Done: returned %d hosts to pool for process %x\n",
  1608.            numReturned, cltPtr->processID);
  1609.     }
  1610.  
  1611.     if (numReturned > 0) {
  1612.     cltPtr->stoleTime = 0;
  1613.     }
  1614.     cltPtr->numInUse -= numReturned;
  1615.     
  1616.     return(returnCode);
  1617.     
  1618. }
  1619.  
  1620.  
  1621. /*
  1622.  *----------------------------------------------------------------------
  1623.  *
  1624.  * InsertIdle --
  1625.  *
  1626.  *    Add a host to the appropriate list of idle hosts, based on
  1627.  *    the priorities with available capacity.  The host must not be
  1628.  *    on any such list when this procedure is called.  
  1629.  *
  1630.  * Results:
  1631.  *    None.
  1632.  *
  1633.  * Side effects:
  1634.  *    Adds host to list, and sets it state based on whether it has
  1635.  *    any capacity already used.
  1636.  *
  1637.  *----------------------------------------------------------------------
  1638.  */
  1639.  
  1640. static void
  1641. InsertIdle(migdPtr)
  1642.     Migd_Info *migdPtr;
  1643. {
  1644.     List_Links *listPtr;
  1645.     List_Links *hdrPtr;
  1646.     int priority;
  1647.     int archType = migdPtr->archType;
  1648.     Mig_Info *infoPtr;
  1649.     Migd_Info *compPtr;
  1650.     int noInput;
  1651.     int found;
  1652.     int origState;
  1653.     
  1654.  
  1655.     WakeupWaiters(archType);
  1656.     infoPtr = &migdPtr->info;
  1657.     noInput = infoPtr->loadVec.noInput;
  1658.     origState = infoPtr->state;
  1659.     List_InitElement((List_Links *) migdPtr);
  1660.     if (List_IsEmpty(&migdPtr->clientList)) {
  1661.     /*
  1662.      * Fast path: host is totally idle, so put it in order
  1663.      * of idle time on the idle list, and before any
  1664.      * hosts with any low priority processes.
  1665.      */
  1666.     hdrPtr = &idleHostsArray[MIG_LOW_PRIORITY][archType];
  1667.     found = 0;
  1668.     LIST_FORALL(hdrPtr, listPtr) {
  1669.         compPtr = (Migd_Info *) listPtr;
  1670.         if (global_Debug > 2) {
  1671.         PRINT_PID;
  1672.         fprintf(stderr, "InsertIdle: comparing %s (%d secs) to %s (%d secs).\n",
  1673.                migdPtr->name, infoPtr->loadVec.noInput, 
  1674.                compPtr->name, compPtr->info.loadVec.noInput);
  1675.         }
  1676.         if (compPtr->info.loadVec.noInput < noInput ||
  1677.         compPtr->info.foreign[MIG_LOW_PRIORITY] > 0) {
  1678.         found = 1;
  1679.         break;
  1680.         }
  1681.     }
  1682.     if (found) {
  1683.         if (global_Debug > 2) {
  1684.         PRINT_PID;
  1685.         fprintf(stderr, "Inserting %s before %s\n",
  1686.                migdPtr->name, compPtr->name);
  1687.         }
  1688.         List_Insert((List_Links *) migdPtr, LIST_BEFORE(listPtr));
  1689.     } else {
  1690.         if (global_Debug > 2) {
  1691.         PRINT_PID;
  1692.         fprintf(stderr, "Inserting %s at end of list\n",
  1693.                migdPtr->name);
  1694.         }
  1695.         List_Insert((List_Links *) migdPtr, LIST_ATREAR(hdrPtr));
  1696.     }
  1697.     infoPtr->state = MIG_HOST_IDLE;
  1698.     goto done;
  1699.     } 
  1700.  
  1701.     /*
  1702.      * Look for the first priority that's filled up and put the process
  1703.      * on the queue for the next higher priority.  If none is filled up,
  1704.      * stick it on the end of the low-prio queue, after the hosts with
  1705.      * no foreign procs at all.
  1706.      */
  1707.  
  1708.     infoPtr->state = MIG_HOST_PART_USED;
  1709.     for (priority = MIG_HIGH_PRIORITY; priority >= MIG_LOW_PRIORITY;
  1710.      priority--) {
  1711.     if (infoPtr->foreign[priority] == infoPtr->maxProcs) {
  1712.         if (priority == MIG_HIGH_PRIORITY) {
  1713.         if (global_Debug > 1) {
  1714.             PRINT_PID;
  1715.             fprintf(stderr, "%s is actually all taken.\n",
  1716.                migdPtr->name);
  1717.         }
  1718.         infoPtr->state = MIG_HOST_FULL;
  1719.         goto done;
  1720.         } else {
  1721.         if (global_Debug > 2) {
  1722.             PRINT_PID;
  1723.             fprintf(stderr, "Inserting %s at end of priority %d\n",
  1724.                migdPtr->name, priority + 1);
  1725.         }
  1726.         List_Insert((List_Links *) migdPtr,
  1727.                 LIST_ATREAR(&idleHostsArray
  1728.                     [priority + 1][archType]));
  1729.         goto done;
  1730.         }
  1731.     }
  1732.     }
  1733.     List_Insert((List_Links *) migdPtr,
  1734.         LIST_ATREAR(&idleHostsArray[MIG_LOW_PRIORITY][archType]));
  1735.  
  1736.     done:
  1737.     /*
  1738.      * If host changed state, modify counters accordingly.
  1739.      */
  1740.     if (origState != infoPtr->state) {
  1741.     hostCounts[archType][origState]--;
  1742.     hostCounts[archType][infoPtr->state]++;
  1743.     }
  1744.     
  1745. }
  1746.  
  1747.  
  1748. /*
  1749.  *----------------------------------------------------------------------
  1750.  *
  1751.  * WakeupWaiters --
  1752.  *
  1753.  *    Check to see if anyone is waiting for an idle host.  Wake up all
  1754.  *    processes waiting for available hosts of this type, if a host is
  1755.  *    available at the appropriate priority.  Then let them ask again for
  1756.  *    an idle host using normal ioctls.
  1757.  *
  1758.  * Results:
  1759.  *    None.
  1760.  *
  1761.  * Side effects:
  1762.  *    Makes pdevs for clients readable so they know to contact us.
  1763.  *
  1764.  *----------------------------------------------------------------------
  1765.  */
  1766.  
  1767. static void
  1768. WakeupWaiters(archType)
  1769.     int archType;
  1770. {
  1771.     List_Links *waitingList;
  1772.     List_Links *listPtr;
  1773.     Migd_WaitList *waitPtr;
  1774.     Migd_OpenStreamInfo *cltPtr;
  1775.     MessageBlock *msgPtr;
  1776.     int curTime;
  1777.     int priority;
  1778.     int i;
  1779.     
  1780.  
  1781.     if (global_Debug > 2) {
  1782.     PRINT_PID;
  1783.     fprintf(stderr,
  1784.            "WakeupWaiters(%s) called.\n", archTypesArray[archType]);
  1785.     }
  1786.     curTime = time(0);
  1787.     for (priority = MIG_HIGH_PRIORITY; priority >= MIG_LOW_PRIORITY;
  1788.      priority--) {
  1789.     if (!List_IsEmpty(&idleHostsArray[priority][archType])) {
  1790.         for (i = priority; i <= MIG_HIGH_PRIORITY; i++) {
  1791.         waitingList = &waitingLists[priority][archType];
  1792.         while (!List_IsEmpty(waitingList)) {
  1793.             /*
  1794.              * For each process waiting, get rid of the info saying it's
  1795.              * waiting and instead add a message to the process.
  1796.              */
  1797.             listPtr = List_First(waitingList);
  1798.             waitPtr = (Migd_WaitList *) listPtr;
  1799.             List_Remove(listPtr);
  1800.             cltPtr = waitPtr->cltPtr;
  1801.             cltPtr->waitPtr = (Migd_WaitList *) NULL;
  1802.             if (cltPtr->stoleTime > curTime - MIGD_STOLE_WINDOW) {
  1803.             if (global_Debug > 0) {
  1804.                 PRINT_PID;
  1805.                 fprintf(stderr,
  1806.                     "\t** not telling process %x about host available, since we stole from it recently.\n",
  1807.                     cltPtr->processID);
  1808.             }
  1809.             } else {
  1810.             TellClient(cltPtr, 0);
  1811.             if (global_Debug > 0) {
  1812.                 PRINT_PID;
  1813.                 fprintf(stderr,
  1814.                     "\t** telling process %x about host available.\n",
  1815.                     cltPtr->processID);
  1816.             }
  1817.             }
  1818.             free((char *) waitPtr);
  1819.         }
  1820.         }
  1821.     }
  1822.     }
  1823. }
  1824.  
  1825.  
  1826.  
  1827.  
  1828. /*
  1829.  *----------------------------------------------------------------------
  1830.  *
  1831.  * RecordEvictions --
  1832.  *
  1833.  *    A host is evicting foreign processes.  Make sure it's marked
  1834.  *    appropriately, and clean up any state from foreign processes.
  1835.  *
  1836.  * Results:
  1837.  *    None.
  1838.  *
  1839.  * Side effects:
  1840.  *    Notifies clients of eviction [eventually].  Frees memory associated
  1841.  *    with outstanding requests for host.
  1842.  *
  1843.  *----------------------------------------------------------------------
  1844.  */
  1845.  
  1846. static void
  1847. RecordEvictions(migdPtr)
  1848.     Migd_Info *migdPtr;
  1849. {
  1850.     int down;
  1851.     List_Links *listPtr;
  1852.     RequestInfo *reqPtr;
  1853.     Migd_OpenStreamInfo *cltPtr;
  1854.     int priority;
  1855.     Mig_ArchStats *archPtr;    /* For statistics. */
  1856.     
  1857.  
  1858.     down = migdPtr->info.state == MIG_HOST_DOWN;
  1859.     if (global_Debug > 2) {
  1860.     PRINT_PID;
  1861.     fprintf(stderr, "RecordEvictions: %s %s.\n",
  1862.            migdPtr->name, down ? "down" : "evicting foreigners");
  1863.     }
  1864.  
  1865.     if (migd_DoStats) {
  1866.     archPtr = &global_Stats.archStats[migdPtr->archType];
  1867.     if (!down) {
  1868.         int noInput = (migdPtr->info.loadVec.noInput + 30) / 60 ;
  1869.         archPtr->nonIdleTransitions++;
  1870.         ADD_WITH_OVERFLOW(archPtr->counters.idleTimeWhenActive,
  1871.                   noInput);
  1872.         ADD_WITH_OVERFLOW(archPtr->squared.idleTimeWhenActive,
  1873.                   noInput * noInput);
  1874.     }
  1875.     }
  1876.  
  1877.  
  1878.     while (!List_IsEmpty(&migdPtr->clientList)) {
  1879.     listPtr = List_First(&migdPtr->clientList);
  1880.     List_Remove(listPtr);
  1881.     reqPtr = NEXT_HOST_REQUEST_TO_INFO(listPtr);
  1882.     if (global_Debug > 1 && !down) {
  1883.         PRINT_PID;
  1884.         fprintf(stderr, "RecordEvictions: %s evicting client %x.\n",
  1885.             migdPtr->name,
  1886.            (reqPtr->flags & MIG_PROC_AGENT) ? 
  1887.            reqPtr->client.processID : 
  1888.            reqPtr->client.cltPtr->processID);
  1889.     }
  1890.     RevokePermission(reqPtr, REVOKE_EVICT);
  1891.         
  1892.     if (migd_DoStats) {
  1893.         int curTime = time(0);
  1894.         int timeToEviction = curTime - reqPtr->timestamp;
  1895.         archPtr->counters.timeToEviction += timeToEviction;
  1896.         archPtr->squared.timeToEviction += timeToEviction * timeToEviction;
  1897.         ADD_WITH_OVERFLOW(archPtr->counters.hostIdleEvicted,
  1898.                   reqPtr->idleTime);
  1899.         ADD_WITH_OVERFLOW(archPtr->squared.hostIdleEvicted,
  1900.                   reqPtr->idleTime * reqPtr->idleTime);
  1901.         
  1902.     }
  1903.     free((char *) reqPtr);
  1904.     }
  1905.     migdPtr->flags &= ~(MIGD_CHECK_COUNT | MIGD_WAS_EMPTY);
  1906.     for (priority = MIG_LOW_PRIORITY; priority <= MIG_HIGH_PRIORITY;
  1907.      priority++) {
  1908.     migdPtr->info.foreign[priority] = 0;
  1909.     }
  1910.     /*
  1911.      * Clear out the last host assignment, since after a machine evicts or
  1912.      * crashes we don't care who last used it.
  1913.      */
  1914.     migdPtr->lastHostAssigned = -1;
  1915.  
  1916.     if (HostIsIdle(migdPtr)) {
  1917.     List_Remove((List_Links *) migdPtr);
  1918.     }
  1919. }
  1920.  
  1921.  
  1922. /*
  1923.  *----------------------------------------------------------------------
  1924.  *
  1925.  * TellClient --
  1926.  *
  1927.  *    Pass a number to a client.  It's either the ID of a host that
  1928.  *    it no longer has permission to use, or 0 to indicate a new host
  1929.  *    may be available.
  1930.  *
  1931.  * Results:
  1932.  *    None.
  1933.  *
  1934.  * Side effects:
  1935.  *    Allocates a message buffer and adds it to the clients list.  Makes
  1936.  *     the client pdev readable.
  1937.  *
  1938.  *----------------------------------------------------------------------
  1939.  */
  1940.  
  1941. static void
  1942. TellClient(cltPtr, msg)
  1943.     Migd_OpenStreamInfo *cltPtr; /* Info about client. */
  1944.     int msg;             /* ID of host, or 0. */
  1945. {
  1946.     MessageBlock *msgPtr;
  1947.  
  1948.     if (global_Debug > 4) {
  1949.     PRINT_PID;
  1950.     fprintf(stderr, "TellClient: telling client %x value %d.\n",
  1951.            cltPtr->processID, msg);
  1952.     }
  1953.     
  1954.     msgPtr = mnew(MessageBlock);
  1955.     List_InitElement(&msgPtr->links);
  1956.     msgPtr->msg = msg;
  1957.     if (List_IsEmpty(&cltPtr->messages)) {
  1958.     MigPdev_MakeReady(cltPtr->streamPtr, (ClientData) NULL);
  1959.     }
  1960.     List_Insert((List_Links *) msgPtr, LIST_ATREAR(&cltPtr->messages));
  1961. }
  1962.  
  1963.  
  1964. /*
  1965.  *----------------------------------------------------------------------
  1966.  *
  1967.  * RevokePermission  --
  1968.  *
  1969.  *    Notify a client that it has lost its permission to use a host.
  1970.  *
  1971.  * Results:
  1972.  *    None.
  1973.  *
  1974.  * Side effects:
  1975.  *    Sends a message.  Removes request from per-client list and per-machine
  1976.  *    list.
  1977.  *
  1978.  *----------------------------------------------------------------------
  1979.  */
  1980.  
  1981. static void
  1982. RevokePermission(reqPtr, action)
  1983.     RequestInfo *reqPtr;
  1984.     RevokeAction action;
  1985. {
  1986.     Migd_Info *migdPtr;
  1987.     Migd_OpenStreamInfo *cltPtr;
  1988.  
  1989.     migdPtr = reqPtr->migdPtr;
  1990.     migdPtr->info.foreign[reqPtr->priority] -= reqPtr->numProcessors;
  1991.     
  1992.     List_Remove(&reqPtr->nextInUse);
  1993. #ifdef DEBUG_LIST_REMOVE
  1994.     /*
  1995.      * Zap the element just to be sure.
  1996.      */
  1997.     List_InitElement(&reqPtr->nextInUse);
  1998. #endif /* DEBUG_LIST_REMOVE */
  1999.     
  2000.     if (!(reqPtr->flags & MIG_PROC_AGENT)) {
  2001.     List_Remove((List_Links *) reqPtr);
  2002.     cltPtr = reqPtr->client.cltPtr;
  2003.     TellClient(cltPtr, migdPtr->info.hostID);
  2004.     cltPtr->numInUse--;
  2005.     if (cltPtr->numInUse == 0) {
  2006.         cltPtr->stoleTime = 0;
  2007.     }
  2008.     if (action == REVOKE_EVICT) {
  2009.         cltPtr->numEvicted++;
  2010.     } else if (action == REVOKE_STOLEN) {
  2011.         cltPtr->numStolen++;
  2012.         cltPtr->stoleTime = time(0);
  2013.     }
  2014.     } else if (action == REVOKE_STOLEN) {
  2015.     /*
  2016.      * Request was on behalf of another process, so we don't
  2017.      * increment the client numStolen field and instead add it
  2018.      * in to the totals independently.  (For regular clients we
  2019.      * accumulate multiple reclaims/client and then the "squared"
  2020.      * statistic weights clustered reclaimed hosts.)
  2021.      */
  2022.     if (migd_DoStats) {
  2023.         global_Stats.archStats[migdPtr->archType].counters.reclaimed++;
  2024.         global_Stats.archStats[migdPtr->archType].squared.reclaimed++;
  2025.     }
  2026.     } else if (action == REVOKE_EVICT) {
  2027.     /*
  2028.      * Request was on behalf of another process, so we don't
  2029.      * increment the client numEvicted field and instead add it
  2030.      * in to the totals independently.  (For regular clients we
  2031.      * accumulate multiple evictions/client and then the "squared"
  2032.      * statistic weights clustered evictions.)
  2033.      */
  2034.     if (migd_DoStats) {
  2035.         global_Stats.archStats[migdPtr->archType].counters.evicted++;
  2036.         global_Stats.archStats[migdPtr->archType].squared.evicted++;
  2037.     }
  2038.     }
  2039. }
  2040.  
  2041.  
  2042. /*
  2043.  *----------------------------------------------------------------------
  2044.  *
  2045.  * Global_GetUpdate --
  2046.  *
  2047.  *    Return an update message to a client.  This is an ioctl
  2048.  *     invoked by the client when the client's stream becomes
  2049.  *    readable.
  2050.  *
  2051.  * Results:
  2052.  *    On error, a non-zero error status is returned, else 0.
  2053.  *
  2054.  * Side effects:
  2055.  *    The message is freed up.  If it's the last message in the
  2056.  *    client's queue, the client is changed to no longer be selectable.
  2057.  *
  2058.  *----------------------------------------------------------------------
  2059.  */
  2060.  
  2061. /* ARGSUSED */
  2062. int
  2063. Global_GetUpdate(cltPtr, command, inBuffer, inBufSize, outBuffer,
  2064.            outBufSizePtr)
  2065.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  2066.                    the request. */
  2067.     int command;        /* Ignored. */
  2068.     char *inBuffer;        /* Buffer to get arguments from, not used. */
  2069.     int inBufSize;        /* Size of the input buffer, not used. */
  2070.     char *outBuffer;        /* Buffer to place results. */
  2071.     int *outBufSizePtr;        /* Size of the output buffer. */
  2072. {
  2073.     int *intPtr;
  2074.     List_Links *listPtr;
  2075.     MessageBlock *msgPtr;
  2076.     
  2077.     if (global_Debug > 1) {
  2078.     PRINT_PID;
  2079.     fprintf(stderr, "Global_GetUpdate called by process %x\n",
  2080.            cltPtr->processID);
  2081.     }
  2082.     if (*outBufSizePtr < sizeof(int)) {
  2083.     if (global_Debug > 0) {
  2084.         SYSLOG2(LOG_WARNING,
  2085.            "Global_GetUpdate: bad output buffer size (%d) from process %x\n",
  2086.            *outBufSizePtr, cltPtr->processID);
  2087.     }
  2088.     return(EINVAL);
  2089.     }
  2090.     if (List_IsEmpty(&cltPtr->messages)) {
  2091.     if (global_Debug > 1) {
  2092.         PRINT_PID;
  2093.         fprintf(stderr,
  2094.            "Global_GetUpdate: no message for process %x\n",
  2095.            cltPtr->processID);
  2096.     }
  2097.     return(EAGAIN);
  2098.     }
  2099.     listPtr = List_First(&cltPtr->messages);
  2100.     List_Remove(listPtr);
  2101.     if (List_IsEmpty(&cltPtr->messages)) {
  2102.     cltPtr->defaultSelBits &= ~FS_READ;
  2103.     }
  2104.     msgPtr = (MessageBlock *) listPtr;
  2105.     intPtr = (int *) outBuffer;
  2106.     *intPtr = msgPtr->msg;
  2107.     *outBufSizePtr = sizeof(int);
  2108.     free((char *) listPtr);
  2109.     if (global_Debug > 1) {
  2110.     PRINT_PID;
  2111.     fprintf(stderr,
  2112.            "Global_GetUpdate: message for process %x is %d\n",
  2113.            cltPtr->processID, msgPtr->msg);
  2114.     }
  2115.     return(0);
  2116. }
  2117.  
  2118.  
  2119.  
  2120. /*
  2121.  *----------------------------------------------------------------------
  2122.  *
  2123.  * Global_RemoveHost --
  2124.  *
  2125.  *    Remove a host completely from the database.  This may be done
  2126.  *    when a host is removed from the system, for example.
  2127.  *
  2128.  * Results:
  2129.  *    On error, a non-zero error status is returned, else 0.
  2130.  *
  2131.  * Side effects:
  2132.  *    The host(s) are removed from our lists and a new checkpoint is
  2133.  *    written.
  2134.  *
  2135.  *----------------------------------------------------------------------
  2136.  */
  2137.  
  2138. /* ARGSUSED */
  2139. int
  2140. Global_RemoveHost(cltPtr, command, inBuffer, inBufSize, outBuffer,
  2141.            outBufSizePtr)
  2142.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  2143.                    the request. */
  2144.     int command;        /* Ignored. */
  2145.     char *inBuffer;        /* Buffer to get arguments from. */
  2146.     int inBufSize;        /* Size of the input buffer. */
  2147.     char *outBuffer;        /* Buffer to place results, not used. */
  2148.     int *outBufSizePtr;        /* Size of the output buffer, set to 0. */
  2149. {
  2150.     int *hostPtr;        /* Pointer into input buffer. */
  2151.     int i;            /* Counter. */
  2152.     int numArgs;        /* Number of args (host IDs). */
  2153.     int status;            /* Status from subroutine calls. */
  2154.  
  2155.     if ((inBufSize % sizeof(int)) != 0 || inBufSize <= 0) {
  2156.     if (global_Debug > 0) {
  2157.         SYSLOG2(LOG_WARNING,
  2158.            "Global_RemoveHost: bad input buffer size (%d) from process %x\n",
  2159.            inBufSize, cltPtr->processID);
  2160.     }
  2161.     return(EINVAL);
  2162.     }
  2163.     numArgs = inBufSize / sizeof(int);
  2164.     hostPtr = (int *) inBuffer;
  2165.     for (i = 0; i < numArgs; i++) {
  2166.     status = RemoveHost(*hostPtr);
  2167.     if (status != 0) {
  2168.         return(status);
  2169.     }
  2170.     }
  2171.     SaveCheckPoint((ClientData) NULL, time_ZeroSeconds);
  2172.     return(0);
  2173. }
  2174.  
  2175.  
  2176.  
  2177. /*
  2178.  *----------------------------------------------------------------------
  2179.  *
  2180.  * RemoveHost --
  2181.  *
  2182.  *    Remove a single host from our knowledge.
  2183.  *
  2184.  * Results:
  2185.  *    On error, a non-zero error status is returned, else 0.
  2186.  *
  2187.  * Side effects:
  2188.  *    None.
  2189.  *
  2190.  *----------------------------------------------------------------------
  2191.  */
  2192.  
  2193. static int
  2194. RemoveHost(hostID)
  2195.     int hostID;            /* Host to remove. */
  2196. {
  2197.     Migd_Info *migdPtr;
  2198.  
  2199.     if (global_Debug > 1) {
  2200.     PRINT_PID;
  2201.     fprintf(stderr, "RemoveHost(%d) -\n", hostID);
  2202.     }
  2203.  
  2204.     if (hostID > maxHosts || hostID <= 0) {
  2205.     if (global_Debug > 0) {
  2206.         PRINT_PID;
  2207.         fprintf(stderr, "RemoveHost: bad value of hostID: %d\n", hostID);
  2208.     }
  2209.     return(EINVAL);
  2210.     }
  2211.     migdPtr = migInfoArray[hostID];
  2212.     if (migdPtr != (Migd_Info *) NULL) {
  2213.     if (migdPtr->info.state != MIG_HOST_DOWN) {
  2214.         if (global_Debug > 0) {
  2215.         PRINT_PID;
  2216.         fprintf(stderr, "RemoveHost: %s is up; not removing.\n",
  2217.             migdPtr->name);
  2218.         }
  2219.         return(EINVAL);
  2220.     }
  2221.     if (migdPtr->name != (char *) NULL) {
  2222.         free(migdPtr->name);
  2223.     }
  2224.     free((char *) migdPtr);
  2225.     migInfoArray[hostID] = (Migd_Info *) NULL;
  2226.     } else if (global_Debug > 0) {
  2227.     PRINT_PID;
  2228.     fprintf(stderr, "RemoveHost(%d) - didn't know about host.\n", hostID);
  2229.     }
  2230.     return(0);
  2231. }
  2232.  
  2233. /*
  2234.  *----------------------------------------------------------------------
  2235.  *
  2236.  * Global_IsHostUp --
  2237.  *
  2238.  *    Return whether the specified host is up.
  2239.  *
  2240.  * Results:
  2241.  *    TRUE if the host exists and is up, FALSE otherwise.
  2242.  *
  2243.  * Side effects:
  2244.  *    None.
  2245.  *
  2246.  *----------------------------------------------------------------------
  2247.  */
  2248.  
  2249. int
  2250. Global_IsHostUp(hostID)
  2251.     int hostID;            /* Host to check on. */
  2252. {
  2253.     Migd_Info *migdPtr;
  2254.  
  2255.     if (global_Debug > 2) {
  2256.     PRINT_PID;
  2257.     fprintf(stderr, "Global_IsHostUp(%d) -\n", hostID);
  2258.     }
  2259.  
  2260.     if (hostID > maxHosts || hostID <= 0) {
  2261.     SYSLOG1(LOG_ERR, "Global_IsHostUp: bad value of hostID: %d\n", hostID);
  2262.     return(0);
  2263.     }
  2264.     migdPtr = migInfoArray[hostID];
  2265.     if ((migdPtr != (Migd_Info *) NULL) &&
  2266.     (migdPtr->info.state != MIG_HOST_DOWN)) {
  2267.     return(1);
  2268.     }
  2269.     return(0);
  2270. }
  2271.  
  2272. /*
  2273.  *----------------------------------------------------------------------
  2274.  *
  2275.  * Global_ChangeState --
  2276.  *
  2277.  *    A host has changed from accepting processes to not accepting them,
  2278.  *    or vice-versa.  If not accepting, then notify processes about
  2279.  *    any evictions that might have occurred.
  2280.  *
  2281.  * Results:
  2282.  *    On error, a non-zero error status is returned, else 0.
  2283.  *
  2284.  * Side effects:
  2285.  *    Message(s) sent to clients.  Host may be added to or removed from
  2286.  *    list of idle hosts.
  2287.  *
  2288.  *----------------------------------------------------------------------
  2289.  */
  2290.  
  2291. /* ARGSUSED */
  2292. int
  2293. Global_ChangeState(cltPtr, command, inBuffer, inBufSize, outBuffer,
  2294.            outBufSizePtr)
  2295.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  2296.                    the request. */
  2297.     int command;        /* Ignored. */
  2298.     char *inBuffer;        /* Buffer to get arguments from. */
  2299.     int inBufSize;        /* Size of the input buffer. */
  2300.     char *outBuffer;        /* Buffer to place results, not used. */
  2301.     int *outBufSizePtr;        /* Size of the output buffer, set to 0. */
  2302. {
  2303.     int *statePtr;
  2304.     int host;
  2305.     Migd_Info *migdPtr;
  2306.  
  2307.     if (cltPtr->type != MIGD_DAEMON) {
  2308.     if (global_Debug > 0) {
  2309.         PRINT_PID;
  2310.         fprintf(stderr,
  2311.            "Global_ChangeState: non-daemon trying to invoke CHANGE ioctl; pid %x state %x\n",
  2312.            cltPtr->processID, (int) cltPtr->type);
  2313.     }
  2314.     return(EPERM);
  2315.     }
  2316.  
  2317.     if (inBufSize != sizeof(int)) {
  2318.     if (global_Debug > 0) {
  2319.         SYSLOG2(LOG_WARNING,
  2320.            "Global_ChangeState: wrong size input (%d bytes) from process %x\n",
  2321.            inBufSize, cltPtr->processID);
  2322.     }
  2323.     return(EINVAL);
  2324.     }
  2325.  
  2326.     host = cltPtr->host;
  2327.     statePtr = (int *) inBuffer;
  2328.  
  2329.     migdPtr = CltToMigd(cltPtr);
  2330.     if (migdPtr == (Migd_Info *) NULL) {
  2331.     SYSLOG0(LOG_ERR, "Global_ChangeState: never heard from this host?  Exiting.\n");
  2332.     exit(1);
  2333.     }
  2334.  
  2335.     if (global_Debug > 2) {
  2336.     PRINT_PID;
  2337.     fprintf(stderr, "Global_ChangeState called for %s => state %d.\n",
  2338.            migdPtr->name,
  2339.            *statePtr);
  2340.     }
  2341.     
  2342.     switch (*statePtr) {
  2343.     case MIG_HOST_ACTIVE:
  2344.     case MIG_HOST_REFUSES: {
  2345.         /*
  2346.          * Host is evicting any foreign processes.
  2347.          */
  2348.         if (global_Debug > 3) {
  2349.         PRINT_PID;
  2350.         fprintf(stderr, "Host is active or is refusing migration.\n");
  2351.         }
  2352.         RecordEvictions(migdPtr);
  2353.         break;
  2354.     }
  2355.     case MIG_HOST_IDLE: {
  2356.         /*
  2357.          * Actually, this case should never be reached.
  2358.          */
  2359.         if (global_Debug > 0) {
  2360.         PRINT_PID;
  2361.         fprintf(stderr, "Changed state to idle??\n");
  2362.         }
  2363.         InsertIdle(migdPtr);
  2364.         break;
  2365.     }
  2366.     default: {
  2367.         PRINT_PID;
  2368.         fprintf(stderr, "Invalid state!\n");
  2369.         return(EINVAL);
  2370.     }
  2371.     }
  2372.     hostCounts[migdPtr->archType][migdPtr->info.state]--;
  2373.     migdPtr->info.state = *statePtr;
  2374.     hostCounts[migdPtr->archType][migdPtr->info.state]++;
  2375.  
  2376.     return(0);
  2377. }
  2378.  
  2379.  
  2380. /*
  2381.  *----------------------------------------------------------------------
  2382.  *
  2383.  * Global_HostUp --
  2384.  *
  2385.  *    Mark a host as being up, the first time its daemon talks to us.
  2386.  *
  2387.  * Results:
  2388.  *    0 for success, or an errno indicating the error.
  2389.  *    EPERM indicates that a non-root process tried to tell us it
  2390.  *     was the daemon.
  2391.  *
  2392.  * Side effects:
  2393.  *    The host is added to the list of active hosts.  
  2394.  *
  2395.  *----------------------------------------------------------------------
  2396.  */
  2397.  
  2398. /* ARGSUSED */
  2399. int
  2400. Global_HostUp(cltPtr, command, inBuffer, inBufSize, outBuffer,
  2401.            outBufSizePtr)
  2402.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  2403.                    the request. */
  2404.     int command;        /* Ignored. */
  2405.     char *inBuffer;        /* Buffer to get arguments from. */
  2406.     int inBufSize;        /* Size of the input buffer. */
  2407.     char *outBuffer;        /* Buffer to place results, not used. */
  2408.     int *outBufSizePtr;        /* Size of the output buffer, set to 0. */
  2409. {
  2410.     Mig_Info *infoPtr;
  2411.     Migd_Info *migdPtr;
  2412.     Host_Entry *hostPtr;
  2413.     Migd_OpenStreamInfo *oldCltPtr;  /* Information about any previous client
  2414.                         from this host. */
  2415.     int status;
  2416.     struct timeval time;
  2417.     
  2418.     if (global_Debug > 3) {
  2419.     PRINT_PID;
  2420.     fprintf(stderr, "Global_HostUp called.\n");
  2421.     }
  2422.  
  2423.     status = gettimeofday(&time, (struct timezone *) NULL);
  2424.     if (status == -1) {
  2425.     SYSLOG1(LOG_ERR, "Error in gettimeofday: %s", strerror(errno));
  2426.     exit(1);
  2427.     }
  2428.  
  2429.     if (inBufSize != sizeof(Mig_Info)) {
  2430.     if (global_Debug > 0) {
  2431.         SYSLOG2(LOG_WARNING,
  2432.            "Global_HostUp: bad input buffer size (%d) from process %x\n",
  2433.            inBufSize, cltPtr->processID);
  2434.     }
  2435.     return(EINVAL);
  2436.     }
  2437.  
  2438.     /*
  2439.      * Flag a connection as belonging to a daemon, permitting
  2440.      * it to perform privileged operations.   Set the format
  2441.      * value in the info struct, so that writes can be swapped if
  2442.      * needed.
  2443.      */
  2444. #ifndef DEBUG
  2445.     if (global_Debug == 0 && cltPtr->user != PROC_SUPER_USER_ID) {
  2446.     return(EPERM);
  2447.     }
  2448. #endif /* DEBUG */
  2449.  
  2450.  
  2451.     infoPtr = (Mig_Info *) inBuffer;
  2452.  
  2453.     if (cltPtr->host > maxHosts) {
  2454.     /*
  2455.      * XXX We should handle this obscure case by growing the array of
  2456.      * hosts, but skip it for the time being.
  2457.      */
  2458.     SYSLOG1(LOG_ERR,
  2459.            "Never heard of host %d, and ID is too big.\n", cltPtr->host);
  2460.     return(EINVAL);
  2461.     }
  2462.     if (migInfoArray[cltPtr->host] == (Migd_Info *) NULL) {
  2463.     /*
  2464.      * This can happen if a new host is added to the system
  2465.      * after the global daemon starts up, or a host record has been
  2466.      * removed. 
  2467.      */
  2468.     hostPtr = Host_ByID(cltPtr->host);
  2469.     if (hostPtr == (Host_Entry *) NULL) {
  2470.         SYSLOG1(LOG_ERR, "No entry in host database for host %d.\n",
  2471.            cltPtr->host);
  2472.         return(EINVAL);
  2473.     }
  2474.     CreateMigdRecord(hostPtr);
  2475.     Host_End();
  2476.     }
  2477.     migdPtr = migInfoArray[cltPtr->host];
  2478.  
  2479.     if (global_Debug > 1) {
  2480.     PRINT_PID;
  2481.     fprintf(stderr,
  2482.         "Global_HostUp - %s pid %x boot %d version %d maxProcs %d\n",
  2483.         migdPtr->name, cltPtr->processID,
  2484.         infoPtr->bootTime, infoPtr->migVersion,
  2485.            infoPtr->maxProcs);
  2486.     }
  2487.  
  2488.     if (migdPtr->cltPtr != (Migd_OpenStreamInfo *) NULL) {
  2489.     oldCltPtr = migdPtr->cltPtr;
  2490.     /*
  2491.      * Check once again whether the host is really down.  If a host reboots
  2492.      * quickly, we might otherwise think it's still up and try to signal
  2493.      * a process.  If we're really unlikely, the host rebooted and the
  2494.      * process of the new daemon is the same as the daemon the last time
  2495.      * the host was up, and we'll kill the new daemon (or some other
  2496.      * random process).  We could solve this problem if each boot
  2497.      * incremented some version number that got passed to the global
  2498.      * daemon, but we don't have such a capability (yet).
  2499.      *
  2500.      * Another potential problem: the host migd gets a stale handle
  2501.      * and closes and reopens the global pdev, and we have to recognize
  2502.      * that and refrain from terminating it as if it were a leftover
  2503.      * migd process.
  2504.      */
  2505.     if (oldCltPtr->processID == cltPtr->processID) {
  2506.         if (global_Debug > 1) {
  2507.         PRINT_PID;
  2508.         fprintf(stderr,
  2509.             "Global_HostUp - %s reopening unclosed connection.\n",
  2510.             migdPtr->name);
  2511.         }
  2512.         (void) Global_HostDown(cltPtr->host, 0);
  2513.     } else if (migdPtr->info.loadVec.timestamp <
  2514.         time.tv_sec - MIG_TIMEOUT) {
  2515.         if (global_Debug > 1) {
  2516.         PRINT_PID;
  2517.         fprintf(stderr,
  2518.             "Global_HostUp - marking %s down (curTime %d, updated %d).\n",
  2519.             migdPtr->name, time.tv_sec,
  2520.             migdPtr->info.loadVec.timestamp);
  2521.         }
  2522.         (void) Global_HostDown(cltPtr->host, 0);
  2523.     }
  2524.     if (migdPtr->info.state != MIG_HOST_DOWN) {
  2525.         if (global_Debug > 1) {
  2526.         PRINT_PID;
  2527.         fprintf(stderr,
  2528.             "Already talking to a daemon on %s.  Signalling pid %x.\n",
  2529.             migdPtr->name, oldCltPtr->processID);
  2530.         }
  2531.         status = Sig_Send(SIG_TERM, oldCltPtr->processID, 0);
  2532.         if (status != SUCCESS) {
  2533.         if (global_Debug > 0) {
  2534.             PRINT_PID;
  2535.             fprintf(stderr, "SendSignal: error sending signal to process %x: %s\n",
  2536.                 oldCltPtr->processID, Stat_GetMsg(status));
  2537.         }
  2538.         Global_HostDown(cltPtr->host, 0);
  2539.         } else {
  2540.         return(EBUSY);
  2541.         }
  2542.     } else {
  2543.         if (global_Debug > 1) {
  2544.         PRINT_PID;
  2545.         fprintf(stderr,
  2546.                "Received new open from host %s; closing prior stream.\n",
  2547.                migdPtr->name);
  2548.         }
  2549.     }
  2550.     } 
  2551.  
  2552.     /*
  2553.      * Check for migds that are a bit confused about their state.
  2554.      */
  2555.     if (infoPtr->state == MIG_HOST_IDLE && !infoPtr->loadVec.allowMigration) {
  2556.     if (global_Debug > 0) {
  2557.         PRINT_PID;
  2558.         fprintf(stderr,
  2559.             "Host %s marked as idle but not allowing migration.\n",
  2560.             migdPtr->name);
  2561.     }
  2562.     infoPtr->state = MIG_HOST_REFUSES;
  2563.     }
  2564. #ifdef USE_GLOBAL_CLOCK
  2565.     /*
  2566.      * Update the time of day to use the global daemon's idea of the time,
  2567.      * to keep things in sync and avoid calling a client down just because
  2568.      * of clock skew.  Check the bootstamp for clock skew too.
  2569.      */
  2570.     infoPtr->loadVec.timestamp = time.tv_sec;
  2571.     if (infoPtr->bootTime > time.tv_sec) {
  2572.     infoPtr->bootTime = time.tv_sec;
  2573.     }
  2574. #endif /* USE_GLOBAL_CLOCK */
  2575.     migdPtr->info = *infoPtr;
  2576.     migdPtr->cltPtr = cltPtr;
  2577.     cltPtr->type = MIGD_DAEMON;
  2578.     cltPtr->defaultSelBits = FS_WRITE;
  2579.  
  2580.     /*
  2581.      * Add the host to appropriate queue, and modify our counters.
  2582.      */
  2583.     hostCounts[migdPtr->archType][MIG_HOST_DOWN]--;
  2584.     hostCounts[migdPtr->archType][infoPtr->state]++;
  2585.     if (infoPtr->state == MIG_HOST_IDLE) {
  2586.     InsertIdle(migdPtr);
  2587.     }
  2588.  
  2589.     hostsUp++;
  2590.     
  2591.     return(0);
  2592. }
  2593.  
  2594.  
  2595.  
  2596. /*
  2597.  *----------------------------------------------------------------------
  2598.  *
  2599.  * EndCallBack --
  2600.  *
  2601.  *    Just a callback used by Fs_Dispatch when we want to quit
  2602.  *    but can't at the moment.  It takes (and ignores) the
  2603.  *    Fs_Dispatch callback arguments.
  2604.  *
  2605.  * Results:
  2606.  *    None.
  2607.  *
  2608.  * Side effects:
  2609.  *    Global_End is called, and the process exits.
  2610.  *
  2611.  *----------------------------------------------------------------------
  2612.  */
  2613.  
  2614. /* ARGSUSED */
  2615. static void
  2616. EndCallBack(clientData, time)
  2617.     ClientData clientData;    /* Generic callback arg, not used.  */
  2618.     Time time;            /* Generic callback arg, not used.  */
  2619. {
  2620.     if (global_Debug > 1) {
  2621.     PRINT_PID;
  2622.     fprintf(stderr, "EndCallBack -\n");
  2623.     }
  2624.     
  2625.     Global_End();
  2626. }
  2627.  
  2628. /*
  2629.  *----------------------------------------------------------------------
  2630.  *
  2631.  * Global_HostDown --
  2632.  *
  2633.  *    Mark a host as being down.  This may happen when a pdev for the
  2634.  *    daemon on that host is closed, or if it doesn't update its information
  2635.  *    in a timely fashion.  If it's really closed, we clean up state
  2636.  *    associated with it.
  2637.  *
  2638.  * Results:
  2639.  *    0 for success, or -1 and an errno for failure.
  2640.  *
  2641.  * Side effects:
  2642.  *    The host is removed from any lists of active hosts.  Any clients
  2643.  *    accessing the host are notified that it is down.
  2644.  *
  2645.  *----------------------------------------------------------------------
  2646.  */
  2647.  
  2648. int
  2649. Global_HostDown(hostID, closed)
  2650.     int hostID;
  2651.     int closed;            /* whether its stream was closed */
  2652. {
  2653.     Migd_Info *migdPtr;
  2654.  
  2655.     if (hostID > maxHosts || migInfoArray[hostID] == (Migd_Info *) NULL) {
  2656.     PRINT_PID;
  2657.     fprintf(stderr, "Global_HostDown: bad value of hostID: %d\n",
  2658.            hostID);
  2659.     errno = EINVAL;
  2660.     return(-1);
  2661.     }
  2662.     migdPtr = migInfoArray[hostID];
  2663.     if (global_Debug > 1) {
  2664.     PRINT_PID;
  2665.     fprintf(stderr, "Global_HostDown(host=%s(%d), closed=%d) called.\n",
  2666.            migdPtr->name, hostID, closed);
  2667.     }
  2668.  
  2669.     if (closed) {
  2670.     /*
  2671.      * We're no longer talking to the daemon with a pdev connection.
  2672.      */
  2673.     migdPtr->cltPtr = (Migd_OpenStreamInfo *) NULL;
  2674.     } else {
  2675.     /*
  2676.      * This connection is unusable... later closes should be ignored.
  2677.      */
  2678.     migdPtr->cltPtr->type = MIGD_CLOSED;
  2679.     }
  2680.     if (HostIsIdle(migdPtr)) {
  2681.     List_Remove((List_Links *) migdPtr);
  2682.     }
  2683.     hostCounts[migdPtr->archType][migdPtr->info.state]--;
  2684.     migdPtr->info.state = MIG_HOST_DOWN;
  2685.     hostCounts[migdPtr->archType][MIG_HOST_DOWN]++;
  2686.     RecordEvictions(migdPtr);
  2687.  
  2688.     hostsUp--;
  2689.     if (hostsUp <= 0 && migd_Quit) {
  2690.     if (closed) {
  2691.         /*
  2692.          * Set up a callback to exit, rather than doing it right now,
  2693.          * since we want to return from any Pdev_Close callback before
  2694.          * trying to close the master.
  2695.          */
  2696.         Fs_TimeoutHandlerDestroy(migd_TimeoutToken);
  2697.         (void) Fs_TimeoutHandlerCreate(time_ZeroSeconds, TRUE,
  2698.                        EndCallBack, (ClientData) NULL);
  2699.     } else {
  2700.         Global_End();
  2701.     }
  2702.     }
  2703.     return(0);
  2704. }
  2705.  
  2706.  
  2707. /*
  2708.  *----------------------------------------------------------------------
  2709.  *
  2710.  * Global_UpdateLoad --
  2711.  *
  2712.  *    Update the load vector corresponding to a host.
  2713.  *
  2714.  * Results:
  2715.  *    0 for success, or -1 for failure, with errno indicating the error.
  2716.  *
  2717.  * Side effects:
  2718.  *    The host may be moved from one queue to another if its status
  2719.  *    changes.
  2720.  *
  2721.  *----------------------------------------------------------------------
  2722.  */
  2723.  
  2724. int
  2725. Global_UpdateLoad(cltPtr, vecPtr)
  2726.     Migd_OpenStreamInfo *cltPtr;
  2727.     Mig_LoadVector *vecPtr;
  2728. {
  2729.     int host;
  2730.     Migd_Info *migdPtr;
  2731.     Mig_LoadVector *oldVecPtr;
  2732.     int oldAllow;
  2733.     int oldForeign;
  2734.     int status;
  2735.     struct timeval time;
  2736.  
  2737.     host = cltPtr->host;
  2738.     
  2739.     migdPtr = CltToMigd(cltPtr);
  2740.     if (migdPtr == (Migd_Info *) NULL) {
  2741.     SYSLOG0(LOG_ERR, "Global_UpdateLoad: never heard from this host?  Exiting.\n");
  2742.     exit(1);
  2743.     }
  2744.     if (global_Debug > 3) {
  2745.     PRINT_PID;
  2746.     fprintf(stderr, "Global_UpdateLoad called for %s. time %d noInput %d foreign %d allowMigration %d utils %d %d %d lengths %.2f %.2f %.2f\n",
  2747.            migdPtr->name,
  2748.            vecPtr->timestamp,
  2749.            vecPtr->noInput,
  2750.            vecPtr->foreignProcs,
  2751.            vecPtr->allowMigration,
  2752.            vecPtr->utils[0], vecPtr->utils[1], vecPtr->utils[2],
  2753.            vecPtr->lengths[0], vecPtr->lengths[1], vecPtr->lengths[2]);
  2754.     }
  2755.     if (migdPtr->info.state == MIG_HOST_DOWN) {
  2756.     if (global_Debug) {
  2757.         PRINT_PID;
  2758.         fprintf(stderr, "Global_UpdateLoad: Thought %s was down.\n",
  2759.            migdPtr->name);
  2760.     }
  2761.     hostCounts[migdPtr->archType][MIG_HOST_DOWN]--;
  2762.     migdPtr->info.state = vecPtr->allowMigration ? MIG_HOST_ACTIVE :
  2763.         MIG_HOST_REFUSES;
  2764.     hostCounts[migdPtr->archType][migdPtr->info.state]++;
  2765.     hostsUp++;
  2766.     }
  2767.     oldVecPtr = &migdPtr->info.loadVec; 
  2768.     if (global_Debug > 3) {
  2769.     PRINT_PID;
  2770.     fprintf(stderr, "Global_UpdateLoad: Old values: time %d noInput %d foreign %d allowMigration %d utils %d %d %d lengths %.2f %.2f %.2f\n",
  2771.            oldVecPtr->timestamp,
  2772.            oldVecPtr->noInput,
  2773.            oldVecPtr->foreignProcs,
  2774.            oldVecPtr->allowMigration,
  2775.            oldVecPtr->utils[0],
  2776.            oldVecPtr->utils[1],
  2777.            oldVecPtr->utils[2],
  2778.            oldVecPtr->lengths[0],
  2779.            oldVecPtr->lengths[1],
  2780.            oldVecPtr->lengths[2]);
  2781.     }
  2782.     oldAllow = oldVecPtr->allowMigration;
  2783.     oldForeign = oldVecPtr->foreignProcs;
  2784.     *oldVecPtr = *vecPtr;
  2785.  
  2786. #ifdef USE_GLOBAL_CLOCK
  2787.     /*
  2788.      * Update the time of day to use the global daemon's idea of the time,
  2789.      * to keep things in sync and avoid calling a client down just because
  2790.      * of clock skew.
  2791.      */
  2792.     status = gettimeofday(&time, (struct timezone *) NULL);
  2793.     if (status == -1) {
  2794.     SYSLOG1(LOG_ERR, "Error in gettimeofday: %s", strerror(errno));
  2795.     exit(1);
  2796.     }
  2797.     oldVecPtr->timestamp = time.tv_sec;
  2798. #endif /* USE_GLOBAL_CLOCK */
  2799.     if (oldAllow && !vecPtr->allowMigration) {
  2800.     /*
  2801.      * Host is evicting any foreign processes.
  2802.      */
  2803.     if (global_Debug > 2) {
  2804.         PRINT_PID;
  2805.         fprintf(stderr, "\t>>%s is no longer available<<\n", migdPtr->name);
  2806.     }
  2807.     if (HostIsIdle(migdPtr)) {
  2808.         List_Remove((List_Links *) migdPtr);
  2809.     }
  2810.     hostCounts[migdPtr->archType][migdPtr->info.state]--;
  2811.     migdPtr->info.state = MIG_HOST_ACTIVE;
  2812.     hostCounts[migdPtr->archType][MIG_HOST_ACTIVE]++;
  2813.     } else if (!oldAllow && vecPtr->allowMigration) {
  2814.     if (global_Debug > 2) {
  2815.         PRINT_PID;
  2816.         fprintf(stderr, "\t<<%s is now idle>>\n", migdPtr->name);
  2817.     }
  2818.     if (HostIsIdle(migdPtr)) {
  2819.         if (global_Debug > 0) {
  2820.         PRINT_PID;
  2821.         fprintf(stderr,
  2822.             "\t ** %s wasn't allowing migration but was idle\n",
  2823.             migdPtr->name);
  2824.         }
  2825.     } else {
  2826.         InsertIdle(migdPtr);
  2827.     }
  2828.     } else if (vecPtr->allowMigration && (migdPtr->flags & MIGD_CHECK_COUNT) &&
  2829.            (migdPtr->info.state == MIG_HOST_FULL ||
  2830.         migdPtr->info.state == MIG_HOST_PART_USED)) {
  2831.     if (oldForeign > 0 && vecPtr->foreignProcs == 0) {
  2832.         if (global_Debug > 1) {
  2833.         PRINT_PID;
  2834.         fprintf(stderr, "\t--%s now has no foreigners--\n",
  2835.             migdPtr->name);
  2836.         }
  2837.         ForceHostIdle(migdPtr);
  2838.     } else if (vecPtr->foreignProcs > 0) {
  2839.         /*
  2840.          * If during a checkpoint we noticed that the host was empty, and
  2841.          * now it isn't, we disable the MIGD_WAS_EMPTY flag.  This
  2842.          * way a host will be marked as having no foreign processes
  2843.          * and put back in the pool only if two checkpoints go by without
  2844.          * the host ever having foreign processes at the points when the
  2845.          * per-host migd sends us its data.
  2846.          */
  2847.         migdPtr->flags &= ~MIGD_WAS_EMPTY;
  2848.     }
  2849.     } else if (vecPtr->allowMigration &&
  2850.            (migdPtr->info.state == MIG_HOST_ACTIVE) &&
  2851.            vecPtr->foreignProcs == 0) {
  2852.     /*
  2853.      * Host must have evicted without later making the transition
  2854.      * from not allowing to allowing.  This can happen if eviction
  2855.      * takes a long time or if eviction is done via an ioctl from
  2856.      * a user rather than by detecting input.
  2857.      */
  2858.     if (global_Debug > 1) {
  2859.         PRINT_PID;
  2860.         fprintf(stderr, "\t--%s available again--\n",
  2861.            migdPtr->name);
  2862.     }
  2863.     ForceHostIdle(migdPtr);
  2864.     }
  2865.     return(0);
  2866. }
  2867.  
  2868.  
  2869. /*
  2870.  *----------------------------------------------------------------------
  2871.  *
  2872.  * RestoreCheckPoint --
  2873.  *
  2874.  *    Restore the last known state of the world from a checkpoint
  2875.  *    file.
  2876.  *
  2877.  * Results:
  2878.  *    None.
  2879.  *
  2880.  * Side effects:
  2881.  *    The state of each host in the checkpoint, and the statistics structure,
  2882.  *    are initialized.
  2883.  *
  2884.  *----------------------------------------------------------------------
  2885.  */
  2886.  
  2887. static void
  2888. RestoreCheckPoint()
  2889. {
  2890.  
  2891.     FILE *checkPoint;
  2892.     int hostID;
  2893.     int timestamp;
  2894.     Migd_Info *migdPtr;
  2895.     int numScanned;
  2896.     int hostsRead = 0;
  2897.     char buffer[BUFSIZ];
  2898.     
  2899.     if (global_Debug > 2) {
  2900.     PRINT_PID;
  2901.     fprintf(stderr, "RestoreCheckPoint -\n");
  2902.     }
  2903.     checkPoint = fopen(MIGD_CHECKPOINT_FILE, "r");
  2904.     if (checkPoint == (FILE *) NULL) {
  2905.     PRINT_PID;
  2906.     fprintf(stderr, "RestoreCheckPoint - error reading checkpoint: %s.\n",
  2907.            strerror(errno));
  2908.     return;
  2909.     }
  2910.     if (ReadStats(checkPoint) < 0) {
  2911.     PRINT_PID;
  2912.     SYSLOG1(stderr,
  2913.         "warning: RestoreCheckPoint - error reading statistics from checkpoint: %s.\n",
  2914.            strerror(errno));
  2915.     /*
  2916.      * Reinitialize statistics buffer.
  2917.      */
  2918.     InitStats();
  2919.     }
  2920.     while (1) {
  2921.     if (fgets(buffer, sizeof(buffer), checkPoint) == (char *) NULL) {
  2922.         break;
  2923.     }
  2924.     if (buffer[0] == '%') {
  2925.         if (global_Debug > 1) {
  2926.         PRINT_PID;
  2927.         fprintf(stderr, "RestoreCheckPoint: %s",
  2928.                buffer);
  2929.         }
  2930.         continue;
  2931.     }
  2932.     numScanned = sscanf(buffer, "%d %d", &hostID, ×tamp);
  2933.     if (numScanned < 0) {
  2934.         break;
  2935.     }
  2936.     if (numScanned != 2) {
  2937.         PRINT_PID;
  2938.         fprintf(stderr,
  2939.            "RestoreCheckPoint - scanned %d items from checkpoint file.\n",
  2940.            numScanned);
  2941.         break;
  2942.     }
  2943.     if (hostID <= 0 || hostID > maxKnownHost) {
  2944.         PRINT_PID;
  2945.         fprintf(stderr,
  2946.            "RestoreCheckPoint - invalid hostID %d.\n", hostID);
  2947.         break;
  2948.     }
  2949.     migdPtr = migInfoArray[hostID];
  2950.     if (migdPtr == (Migd_Info *) NULL ||
  2951.         migdPtr->info.loadVec.timestamp != 0) {
  2952.         PRINT_PID;
  2953.         fprintf(stderr,
  2954.            "RestoreCheckPoint - host %d NULL or non-zero.\n", hostID);
  2955.         break;
  2956.     }
  2957.     if (global_Debug > 2) {
  2958.         fprintf(stderr,
  2959.            "<%d,%d> ",
  2960.            hostID, timestamp);
  2961.     }
  2962.     migdPtr->info.loadVec.timestamp = timestamp;
  2963.     if (migdPtr->info.state != MIG_HOST_DOWN) {
  2964.         panic("RestoreCheckPoint: host was not in DOWN state before.\n");
  2965.     }
  2966.     hostsRead++;
  2967.     }
  2968.     if (global_Debug > 1) {
  2969.     fprintf(stderr, "\n%x: RestoreCheckPoint - read %d hosts.\n",
  2970.         migd_Pid, hostsRead);
  2971.     }
  2972.     (void) fclose(checkPoint);
  2973. }
  2974.  
  2975.  
  2976. /*
  2977.  *----------------------------------------------------------------------
  2978.  *
  2979.  * SaveCheckPoint --
  2980.  *
  2981.  *    Save the last known state of the world to a checkpoint
  2982.  *    file.  While we're at it, check for hosts we haven't heard from
  2983.  *    in a while, and check to make sure we're still controlling the
  2984.  *     real master pdev (someone else could have mistakenly removed it
  2985.  *     and started a second master, and new contacts would reach it instead
  2986.  *     of this process).
  2987.  *
  2988.  * Results:
  2989.  *    None.
  2990.  *
  2991.  * Side effects:
  2992.  *    Hosts may be marked as DOWN.
  2993.  *
  2994.  *----------------------------------------------------------------------
  2995.  */
  2996.  
  2997. /* ARGSUSED */
  2998. static void
  2999. SaveCheckPoint(clientData, timeArg)
  3000.     ClientData clientData;    /* Generic callback arg, not used.  */
  3001.     Time timeArg;        /* Generic callback arg, not used.  */
  3002. {
  3003.     FILE *checkPoint;
  3004.     Migd_Info *migdPtr;
  3005.     int i;
  3006.     struct timeval tv;
  3007.     int status;
  3008.     struct stat nameAtts;
  3009.     
  3010.     if (global_Debug > 1) {
  3011.     int t = time(0);
  3012.     PRINT_PID;
  3013.     fprintf(stderr, "Global daemon checkpoint: running on %s at %s",
  3014.         migd_HostName, ctime(&t));
  3015.     }
  3016.  
  3017. #ifdef 0
  3018.     if (lstat(migd_GlobalPdevName, &nameAtts) < 0) {
  3019.     SYSLOG2(LOG_ERR, "Exiting: unable to stat %s: %s.\n",
  3020.            migd_GlobalPdevName, strerror(errno));
  3021.     exit(1);
  3022.     }
  3023. #endif
  3024.     if (lstat(MIGD_LOCK_FILE, &nameAtts) < 0) {
  3025.     SYSLOG2(LOG_ERR, "Exiting: unable to stat %s: %s.\n",
  3026.            MIGD_LOCK_FILE, strerror(errno));
  3027.     exit(1);
  3028.     }
  3029.     if (nameAtts.st_ino != descAtts.st_ino ||
  3030.     nameAtts.st_version != descAtts.st_version) {
  3031.     SYSLOG3(LOG_WARNING,
  3032.            "Exiting: mismatch statting files: name inode <%d,%d>, version %d.\n",
  3033.            nameAtts.st_ino, nameAtts.st_devServerID, nameAtts.st_version);
  3034.     SYSLOG3(LOG_WARNING,
  3035.            "\tdescriptor inode <%d,%d> version %d (another migd running, or server changed file version).\n",
  3036.            descAtts.st_ino, descAtts.st_devServerID, descAtts.st_version);
  3037.     exit(1);
  3038.     }
  3039.  
  3040.     if (global_Debug > 4) {
  3041.     PRINT_PID;
  3042.     fprintf(stderr, "Descriptors matched okay.\n");
  3043.     }
  3044.     
  3045.  
  3046.     checkPoint = fopen(MIGD_CHECKPOINT_FILE, "w+");
  3047.     if (checkPoint == (FILE *) NULL) {
  3048.     SYSLOG1(LOG_WARNING, "SaveCheckPoint - error writing checkpoint: %s.\n",
  3049.            strerror(errno));
  3050.     return;
  3051.     }
  3052.     status = gettimeofday(&tv, (struct timezone *) NULL);
  3053.     if (status == -1) {
  3054.     SYSLOG1(LOG_ERR, "Error in gettimeofday: %s", strerror(errno));
  3055.     exit(1);
  3056.     }
  3057.  
  3058.     if (migd_DoStats) {
  3059.     DumpStats(checkPoint);
  3060.     }
  3061.  
  3062.     for (i = 1; i <= maxKnownHost; i++) {
  3063.     migdPtr = migInfoArray[i];
  3064.     if (migdPtr == (Migd_Info *) NULL ||
  3065.         migdPtr->info.loadVec.timestamp == 0) {
  3066.         continue;
  3067.     }
  3068.     if (fprintf(checkPoint, "%d %d\n", migdPtr->info.hostID,
  3069.             migdPtr->info.loadVec.timestamp) < 0) {
  3070.         SYSLOG1(LOG_WARNING,
  3071.            "SaveCheckPoint - error writing record to checkpoint file: %s.\n",
  3072.            strerror(errno));
  3073.         if (global_Debug == 0) {
  3074.         (void) unlink(MIGD_CHECKPOINT_FILE);
  3075.         }
  3076.     }
  3077.     if (migdPtr->info.state != MIG_HOST_DOWN &&
  3078.         migdPtr->info.loadVec.timestamp < tv.tv_sec - MIG_TIMEOUT) {
  3079.         if (global_Debug > 1) {
  3080.         PRINT_PID;
  3081.         fprintf(stderr,
  3082.                "SaveCheckPoint - marking %s down (curTime %d, updated %d).\n",
  3083.                migdPtr->name, tv.tv_sec,
  3084.                migdPtr->info.loadVec.timestamp);
  3085.         }
  3086.         (void) Global_HostDown(i, 0);
  3087.     } else if (migdPtr->info.loadVec.foreignProcs == 0 &&
  3088.            migdPtr->info.loadVec.allowMigration &&
  3089.            (migdPtr->info.state == MIG_HOST_PART_USED ||
  3090.             migdPtr->info.state == MIG_HOST_FULL)) {
  3091.         if (global_Debug > 1) {
  3092.         PRINT_PID;
  3093.         fprintf(stderr,
  3094.                "SaveCheckPoint - checking %s foreign count.\n",
  3095.                migdPtr->name);
  3096.         }
  3097.         
  3098.         if (migdPtr->flags & MIGD_WAS_EMPTY) {
  3099.         ForceHostIdle(migdPtr);
  3100.         } else {
  3101.         migdPtr->flags |= MIGD_WAS_EMPTY;
  3102.         }
  3103.     } 
  3104.     }
  3105.     fflush(checkPoint);
  3106.     if (fsync(fileno(checkPoint)) < 0) {
  3107.     SYSLOG0(LOG_WARNING, "Error syncing checkpoint file to disk.\n");
  3108.     }
  3109.     (void) fclose(checkPoint);
  3110. }
  3111.     
  3112.  
  3113. /*
  3114.  *----------------------------------------------------------------------
  3115.  *
  3116.  * DumpStats --
  3117.  *
  3118.  *    Write statistics out in ASCII to the checkpoint file.
  3119.  *
  3120.  * Results:
  3121.  *    None.
  3122.  *
  3123.  * Side effects:
  3124.  *    None.
  3125.  *
  3126.  *----------------------------------------------------------------------
  3127.  */
  3128.  
  3129. static void
  3130. DumpStats(file)
  3131.     FILE *file;
  3132. {
  3133.     int i, j;
  3134.  
  3135.     global_Stats.intervals++;
  3136.     
  3137.     fprintf(file, "%% Version %u HasStats %u Interval %u last run on %s.\n",
  3138.         migd_Version, migd_DoStats, global_CheckpointInterval,
  3139.         migd_HostName);
  3140.     fprintf(file, "%% firstRun %u\n", global_Stats.firstRun);
  3141.     fprintf(file, "%% restarts %u\n", global_Stats.restarts);
  3142.     fprintf(file, "%% intervals %u\n", global_Stats.intervals);
  3143.     fprintf(file, "%% maxArchs %u\n", global_Stats.maxArchs);
  3144.     fprintf(file, "%% getLoadRequests %u\n", global_Stats.getLoadRequests);
  3145.     fprintf(file, "%% totalRequests %u\n", global_Stats.totalRequests);
  3146.     fprintf(file, "%% totalObtained %u\n", global_Stats.totalObtained);
  3147.     fprintf(file, "%% numRepeatRequests %u\n", global_Stats.numRepeatRequests);
  3148.     fprintf(file, "%% numRepeatAssignments %u\n",
  3149.         global_Stats.numRepeatAssignments);
  3150.     fprintf(file, "%% numFirstAssignments %u\n",
  3151.         global_Stats.numFirstAssignments);
  3152.     for (i = 0; i < global_Stats.maxArchs; i++) {
  3153.     fprintf(file, "%% arch %u %s\n",
  3154.         i, global_Stats.archStats[i].arch);
  3155.     fprintf(file, "%% \tnumClients %u\n",
  3156.         global_Stats.archStats[i].numClients);
  3157.     fprintf(file, "%% \tgotAll %u\n",
  3158.         global_Stats.archStats[i].gotAll);
  3159.     fprintf(file, "%% \tnonIdleTransitions %u\n",
  3160.         global_Stats.archStats[i].nonIdleTransitions);
  3161.  
  3162.     fprintf(file, "%% \trequested %u %u\n",
  3163.         global_Stats.archStats[i].counters.requested,
  3164.         global_Stats.archStats[i].squared.requested);
  3165.     fprintf(file, "%% \tobtained %u %u\n",
  3166.         global_Stats.archStats[i].counters.obtained,
  3167.         global_Stats.archStats[i].squared.obtained);
  3168.     fprintf(file, "%% \tevicted %u %u\n",
  3169.         global_Stats.archStats[i].counters.evicted,
  3170.         global_Stats.archStats[i].squared.evicted);
  3171.     fprintf(file, "%% \treclaimed %u %u\n",
  3172.         global_Stats.archStats[i].counters.reclaimed,
  3173.         global_Stats.archStats[i].squared.reclaimed);
  3174.     fprintf(file, "%% \ttimeUsed %u %u\n",
  3175.         global_Stats.archStats[i].counters.timeUsed,
  3176.         global_Stats.archStats[i].squared.timeUsed);
  3177.     fprintf(file, "%% \ttimeToEviction %u %u\n",
  3178.         global_Stats.archStats[i].counters.timeToEviction,
  3179.         global_Stats.archStats[i].squared.timeToEviction);
  3180.     fprintf(file, "%% \thostIdleObtained %u %u %u %u\n",
  3181.         global_Stats.archStats[i].counters.hostIdleObtained[MIG_COUNTER_HIGH],
  3182.         global_Stats.archStats[i].counters.hostIdleObtained[MIG_COUNTER_LOW],
  3183.         global_Stats.archStats[i].squared.hostIdleObtained[MIG_COUNTER_HIGH],
  3184.         global_Stats.archStats[i].squared.hostIdleObtained[MIG_COUNTER_LOW]);
  3185.     fprintf(file, "%% \thostIdleEvicted %u %u %u %u\n",
  3186.         global_Stats.archStats[i].counters.hostIdleEvicted[MIG_COUNTER_HIGH],
  3187.         global_Stats.archStats[i].counters.hostIdleEvicted[MIG_COUNTER_LOW],
  3188.         global_Stats.archStats[i].squared.hostIdleEvicted[MIG_COUNTER_HIGH],
  3189.         global_Stats.archStats[i].squared.hostIdleEvicted[MIG_COUNTER_LOW]);
  3190.     fprintf(file, "%% \tidleTimeWhenActive %u %u %u %u\n",
  3191.         global_Stats.archStats[i].counters.idleTimeWhenActive[MIG_COUNTER_HIGH],
  3192.         global_Stats.archStats[i].counters.idleTimeWhenActive[MIG_COUNTER_LOW],
  3193.         global_Stats.archStats[i].squared.idleTimeWhenActive[MIG_COUNTER_HIGH],
  3194.         global_Stats.archStats[i].squared.idleTimeWhenActive[MIG_COUNTER_LOW]);
  3195.  
  3196.     fprintf(file, "%% \trequestDist ");
  3197.     for (j = 0; j <= MIG_MAX_HOSTS_DIST; j++) {
  3198.         fprintf(file, "%u ",
  3199.             global_Stats.archStats[i].requestDist[j]);
  3200.     }
  3201.     fprintf(file, "\n");
  3202.  
  3203.     fprintf(file, "%% \tobtainedDist ");
  3204.     for (j = 0; j <= MIG_MAX_HOSTS_DIST; j++) {
  3205.         fprintf(file, "%u ",
  3206.             global_Stats.archStats[i].obtainedDist[j]);
  3207.     }
  3208.     fprintf(file, "\n");
  3209.  
  3210.     fprintf(file, "%% \thostCounts ");
  3211.     for (j = 0; j < MIG_NUM_STATES; j++) {
  3212.         global_Stats.archStats[i].counters.hostCounts[j] +=
  3213.         hostCounts[i][j];
  3214.         global_Stats.archStats[i].squared.hostCounts[j] +=
  3215.         hostCounts[i][j] * hostCounts[i][j];
  3216.         fprintf(file, "%u %u ",
  3217.             global_Stats.archStats[i].counters.hostCounts[j],
  3218.             global_Stats.archStats[i].squared.hostCounts[j]);
  3219.     }
  3220.     fprintf(file, "\n");
  3221.     }
  3222.     fprintf(file, "%% End of Statistics\n");
  3223.  
  3224. /*
  3225.  *----------------------------------------------------------------------
  3226.  *
  3227.  * ReadStats --
  3228.  *
  3229.  *    Read statistics in ASCII format from the checkpoint file.  
  3230.  *
  3231.  * Results:
  3232.  *    If we are the wrong version, or we hit some error, we return -1.
  3233.  *    That indicates that the caller should just ignore any subsequent
  3234.  *    lines with "%" in them.  0 indicates success.
  3235.  *
  3236.  * Side effects:
  3237.  *    Statistics are reset from last checkpoint.
  3238.  *
  3239.  *----------------------------------------------------------------------
  3240.  */
  3241.  
  3242. static int
  3243. ReadStats(file)
  3244.     FILE *file;
  3245. {
  3246.     int i, j;
  3247.     int numScanned;
  3248.     char buffer[BUFSIZ];
  3249.     int lineNum = 0;
  3250.     int lastVersion;        /* Version of migd that wrote checkpoint. */
  3251.     int lastInterval;        /* Checkpoint interval  of migd that wrote
  3252.                    checkpoint. */
  3253.     int didStats;        /* Whether that migd wrote the statistics. */
  3254.     int maxArchs;        /* Value of global_Stats.maxArchs for that
  3255.                    migd. */
  3256.     int archNum;        /* Index into archTypes array. */
  3257.     char archName[BUFSIZ];    /* Temporary buffer for name, to compare
  3258.                    against our index. */
  3259.     
  3260. /*
  3261.  * Common action to take on bad input.
  3262.  */
  3263. #define BAD_INPUT \
  3264.     if (global_Debug > 1) { \
  3265.     PRINT_PID; \
  3266.     fprintf(stderr, \
  3267.         "ReadStats: bad input on line %d: %s", \
  3268.         lineNum, buffer); \
  3269.     } \
  3270.     return(-1); 
  3271.  
  3272.  
  3273.  
  3274. /*
  3275.  * For each line, read the whole thing into a buffer (1) to make sure
  3276.  * it starts with "%" and (2) to be able to print it out entirely
  3277.  * if there's a problem.
  3278.  */
  3279. #define READLINE \
  3280.     if (fgets(buffer, sizeof(buffer), file) == (char *) NULL) { \
  3281.     if (global_Debug > 1) { \
  3282.         PRINT_PID; \
  3283.         fprintf(stderr, \
  3284.             "ReadStats: end of file at line %d.\n", lineNum); \
  3285.     } \
  3286.     return(-1); \
  3287.     } \
  3288.     lineNum++; \
  3289.     if (buffer[0] != '%') { \
  3290.         BAD_INPUT; \
  3291.     }
  3292.  
  3293.     READLINE;
  3294.     
  3295.     if (global_Debug > 1) {
  3296.     PRINT_PID;
  3297.     fprintf(stderr, "ReadStats: %s", buffer);
  3298.     }
  3299.     
  3300.     numScanned = sscanf(buffer, "%% Version %u HasStats %u Interval %u",
  3301.         &lastVersion, &didStats, &lastInterval);
  3302.     if (numScanned != 3) {
  3303.     BAD_INPUT;
  3304.     }
  3305.     if (lastVersion != migd_Version ||
  3306.     lastInterval != global_CheckpointInterval) {
  3307.     if (global_Debug > 1) { 
  3308.         PRINT_PID; 
  3309.         fprintf(stderr, 
  3310.             "ReadStats: mismatch in migd versions or intervals: ours is %u, %u but last writer\n\tof checkpoint was %u, %u.\n",
  3311.             migd_Version, global_CheckpointInterval,
  3312.             lastVersion, lastInterval); 
  3313.     } 
  3314.     return(-1); 
  3315.     }
  3316.     if (didStats != 1) {
  3317.     if (global_Debug > 1) { 
  3318.         PRINT_PID; 
  3319.         fprintf(stderr, 
  3320.             "ReadStats: last writer of checkpoint didn't do stats.\n"); 
  3321.     } 
  3322.     return(0);
  3323.     }
  3324.  
  3325.  
  3326.     READLINE;
  3327.     numScanned = sscanf(buffer, "%% firstRun %u", &global_Stats.firstRun);
  3328.     if (numScanned != 1) {
  3329.     BAD_INPUT;
  3330.     }
  3331.     
  3332.     READLINE;
  3333.     numScanned = sscanf(buffer, "%% restarts %u", &global_Stats.restarts);
  3334.     if (numScanned != 1) {
  3335.     BAD_INPUT;
  3336.     }
  3337.     global_Stats.restarts++;
  3338.  
  3339.     READLINE;
  3340.     numScanned = sscanf(buffer, "%% intervals %u", &global_Stats.intervals);
  3341.     if (numScanned != 1) {
  3342.     BAD_INPUT;
  3343.     }
  3344.  
  3345.     READLINE;
  3346.     numScanned = sscanf(buffer, "%% maxArchs %u", &maxArchs);
  3347.     if (numScanned != 1) {
  3348.     BAD_INPUT;
  3349.     }
  3350.     if (maxArchs != global_Stats.maxArchs) {
  3351.     if (global_Debug > 1) { 
  3352.         PRINT_PID; 
  3353.         fprintf(stderr, 
  3354.             "ReadStats: discrepancy in number of architectures managed by\n\tmigd; resetting statistics.\n"); 
  3355.     } 
  3356.     return(-1);
  3357.     }
  3358.     
  3359.     READLINE;
  3360.     numScanned = sscanf(buffer, "%% getLoadRequests %u",
  3361.             &global_Stats.getLoadRequests);
  3362.     if (numScanned != 1) {
  3363.     BAD_INPUT;
  3364.     }
  3365.  
  3366.     READLINE;
  3367.     numScanned = sscanf(buffer, "%% totalRequests %u",
  3368.             &global_Stats.totalRequests);
  3369.     if (numScanned != 1) {
  3370.     BAD_INPUT;
  3371.     }
  3372.  
  3373.     READLINE;
  3374.     numScanned = sscanf(buffer, "%% totalObtained %u",
  3375.             &global_Stats.totalObtained);
  3376.     if (numScanned != 1) {
  3377.     BAD_INPUT;
  3378.     }
  3379.  
  3380.     READLINE;
  3381.     numScanned = sscanf(buffer, "%% numRepeatRequests %u",
  3382.             &global_Stats.numRepeatRequests);
  3383.     if (numScanned != 1) {
  3384.     BAD_INPUT;
  3385.     }
  3386.  
  3387.     READLINE;
  3388.     numScanned = sscanf(buffer, "%% numRepeatAssignments %u",
  3389.             &global_Stats.numRepeatAssignments);
  3390.     if (numScanned != 1) {
  3391.     BAD_INPUT;
  3392.     }
  3393.  
  3394.     READLINE;
  3395.     numScanned = sscanf(buffer, "%% numFirstAssignments %u",
  3396.             &global_Stats.numFirstAssignments);
  3397.     if (numScanned != 1) {
  3398.     BAD_INPUT;
  3399.     }
  3400.  
  3401.     for (i = 0; i < maxArchs; i++) {
  3402.     READLINE;
  3403.     numScanned = sscanf(buffer, "%% arch %u %s", &archNum, archName);
  3404.     if (numScanned != 2) {
  3405.         BAD_INPUT;
  3406.     }
  3407.     if (archNum != i || strcmp(archName, global_Stats.archStats[i].arch)) {
  3408.         BAD_INPUT;
  3409.     }
  3410.  
  3411.     READLINE;
  3412.     numScanned = sscanf(buffer, "%% \tnumClients %u",
  3413.         &global_Stats.archStats[i].numClients);
  3414.     if (numScanned != 1) {
  3415.         BAD_INPUT;
  3416.     }
  3417.     
  3418.     READLINE;
  3419.     numScanned = sscanf(buffer, "%% \tgotAll %u",
  3420.         &global_Stats.archStats[i].gotAll);
  3421.     if (numScanned != 1) {
  3422.         BAD_INPUT;
  3423.     }
  3424.     
  3425.     READLINE;
  3426.     numScanned = sscanf(buffer, "%% \tnonIdleTransitions %u",
  3427.         &global_Stats.archStats[i].nonIdleTransitions);
  3428.     if (numScanned != 1) {
  3429.         BAD_INPUT;
  3430.     }
  3431.  
  3432.     READLINE;
  3433.     numScanned = sscanf(buffer, "%% \trequested %u %u",
  3434.         &global_Stats.archStats[i].counters.requested,
  3435.         &global_Stats.archStats[i].squared.requested);
  3436.     if (numScanned != 2) {
  3437.         BAD_INPUT;
  3438.     }
  3439.     READLINE;
  3440.     numScanned = sscanf(buffer, "%% \tobtained %u %u",
  3441.         &global_Stats.archStats[i].counters.obtained,
  3442.         &global_Stats.archStats[i].squared.obtained);
  3443.     if (numScanned != 2) {
  3444.         BAD_INPUT;
  3445.     }
  3446.     READLINE;
  3447.     numScanned = sscanf(buffer, "%% \tevicted %u %u",
  3448.         &global_Stats.archStats[i].counters.evicted,
  3449.         &global_Stats.archStats[i].squared.evicted);
  3450.     if (numScanned != 2) {
  3451.         BAD_INPUT;
  3452.     }
  3453.     READLINE;
  3454.     numScanned = sscanf(buffer, "%% \treclaimed %u %u",
  3455.         &global_Stats.archStats[i].counters.reclaimed,
  3456.         &global_Stats.archStats[i].squared.reclaimed);
  3457.  
  3458.     if (numScanned != 2) {
  3459.         BAD_INPUT;
  3460.     }
  3461.     READLINE;
  3462.     numScanned = sscanf(buffer, "%% \ttimeUsed %u %u",
  3463.         &global_Stats.archStats[i].counters.timeUsed,
  3464.         &global_Stats.archStats[i].squared.timeUsed);
  3465.  
  3466.     if (numScanned != 2) {
  3467.         BAD_INPUT;
  3468.     }
  3469.     READLINE;
  3470.     numScanned = sscanf(buffer, "%% \ttimeToEviction %u %u",
  3471.         &global_Stats.archStats[i].counters.timeToEviction,
  3472.         &global_Stats.archStats[i].squared.timeToEviction);
  3473.  
  3474.     if (numScanned != 2) {
  3475.         BAD_INPUT;
  3476.     }
  3477.     READLINE;
  3478.     numScanned = sscanf(buffer, "%% \thostIdleObtained %u %u %u %u",
  3479.         &global_Stats.archStats[i].counters.hostIdleObtained[MIG_COUNTER_HIGH],
  3480.         &global_Stats.archStats[i].counters.hostIdleObtained[MIG_COUNTER_LOW],
  3481.         &global_Stats.archStats[i].squared.hostIdleObtained[MIG_COUNTER_HIGH],
  3482.         &global_Stats.archStats[i].squared.hostIdleObtained[MIG_COUNTER_LOW]);
  3483.  
  3484.     if (numScanned != 4) {
  3485.         BAD_INPUT;
  3486.     }
  3487.     READLINE;
  3488.     numScanned = sscanf(buffer, "%% \thostIdleEvicted %u %u %u %u",
  3489.         &global_Stats.archStats[i].counters.hostIdleEvicted[MIG_COUNTER_HIGH],
  3490.         &global_Stats.archStats[i].counters.hostIdleEvicted[MIG_COUNTER_LOW],
  3491.         &global_Stats.archStats[i].squared.hostIdleEvicted[MIG_COUNTER_HIGH],
  3492.         &global_Stats.archStats[i].squared.hostIdleEvicted[MIG_COUNTER_LOW]);
  3493.  
  3494.     if (numScanned != 4) {
  3495.         BAD_INPUT;
  3496.     }
  3497.     READLINE;
  3498.     numScanned = sscanf(buffer, "%% \tidleTimeWhenActive %u %u %u %u",
  3499.         &global_Stats.archStats[i].counters.idleTimeWhenActive[MIG_COUNTER_HIGH],
  3500.         &global_Stats.archStats[i].counters.idleTimeWhenActive[MIG_COUNTER_LOW],
  3501.         &global_Stats.archStats[i].squared.idleTimeWhenActive[MIG_COUNTER_HIGH],
  3502.         &global_Stats.archStats[i].squared.idleTimeWhenActive[MIG_COUNTER_LOW]);
  3503.     if (numScanned != 4) {
  3504.         BAD_INPUT;
  3505.     }
  3506.     /*
  3507.      * No easy way to use sscanf to go through a string piece
  3508.      * by piece, so use fscanf.  First for distribution of requests,
  3509.      * then count of hosts.
  3510.      */
  3511.     numScanned = fscanf(file, "%% \trequestDist");
  3512.     if (numScanned < 0) {
  3513.         if (global_Debug > 1) { 
  3514.         PRINT_PID; 
  3515.         fprintf(stderr, 
  3516.             "ReadStats: error scanning requestDist line (%d).\n",
  3517.             lineNum); 
  3518.         } 
  3519.         return(-1);
  3520.     }        
  3521.     for (j = 0; j <= MIG_MAX_HOSTS_DIST; j++) {
  3522.         numScanned = fscanf(file, "%u ",
  3523.                 &global_Stats.archStats[i].requestDist[j]);
  3524.         if (numScanned != 1) {
  3525.         if (global_Debug > 1) { 
  3526.             PRINT_PID; 
  3527.             fprintf(stderr, 
  3528.                 "ReadStats: error scanning requestDist line (%d).\n",
  3529.                 lineNum); 
  3530.         } 
  3531.         return(-1);
  3532.         }        
  3533.     }
  3534.     numScanned = fscanf(file, "\n");
  3535.     if (numScanned < 0) {
  3536.         if (global_Debug > 1) { 
  3537.         PRINT_PID; 
  3538.         fprintf(stderr, 
  3539.             "ReadStats: error scanning requestDist line (%d).\n",
  3540.             lineNum); 
  3541.         } 
  3542.         return(-1);
  3543.     }        
  3544.     lineNum++;
  3545.  
  3546.     numScanned = fscanf(file, "%% \tobtainedDist");
  3547.     if (numScanned < 0) {
  3548.         if (global_Debug > 1) { 
  3549.         PRINT_PID; 
  3550.         fprintf(stderr, 
  3551.             "ReadStats: error scanning obtainedDist line (%d).\n",
  3552.             lineNum); 
  3553.         } 
  3554.         return(-1);
  3555.     }        
  3556.     for (j = 0; j <= MIG_MAX_HOSTS_DIST; j++) {
  3557.         numScanned = fscanf(file, "%u ",
  3558.                 &global_Stats.archStats[i].obtainedDist[j]);
  3559.         if (numScanned != 1) {
  3560.         if (global_Debug > 1) { 
  3561.             PRINT_PID; 
  3562.             fprintf(stderr, 
  3563.                 "ReadStats: error scanning obtainedDist line (%d).\n",
  3564.                 lineNum); 
  3565.         } 
  3566.         return(-1);
  3567.         }        
  3568.     }
  3569.     numScanned = fscanf(file, "\n");
  3570.     if (numScanned < 0) {
  3571.         if (global_Debug > 1) { 
  3572.         PRINT_PID; 
  3573.         fprintf(stderr, 
  3574.             "ReadStats: error scanning obtainedDist line (%d).\n",
  3575.             lineNum); 
  3576.         } 
  3577.         return(-1);
  3578.     }        
  3579.     lineNum++;
  3580.  
  3581.     numScanned = fscanf(file, "%% \thostCounts");
  3582.     if (numScanned < 0) {
  3583.         if (global_Debug > 1) { 
  3584.         PRINT_PID; 
  3585.         fprintf(stderr, 
  3586.             "ReadStats: error scanning hostCounts line (%d).\n",
  3587.             lineNum); 
  3588.         } 
  3589.         return(-1);
  3590.     }        
  3591.     for (j = 0; j < MIG_NUM_STATES; j++) {
  3592.         numScanned = fscanf(file, "%u %u ",
  3593.                 &global_Stats.archStats[i].counters.hostCounts[j],
  3594.                 &global_Stats.archStats[i].squared.hostCounts[j]);
  3595.         if (numScanned != 2) {
  3596.         if (global_Debug > 1) { 
  3597.             PRINT_PID; 
  3598.             fprintf(stderr, 
  3599.                 "ReadStats: error scanning hostCounts line (%d).\n",
  3600.                 lineNum); 
  3601.         } 
  3602.         return(-1);
  3603.         }        
  3604.     }
  3605.     numScanned = fscanf(file, "\n");
  3606.     if (numScanned < 0) {
  3607.         if (global_Debug > 1) { 
  3608.         PRINT_PID; 
  3609.         fprintf(stderr, 
  3610.             "ReadStats: error scanning hostCounts line (%d).\n",
  3611.             lineNum); 
  3612.         } 
  3613.         return(-1);
  3614.     }        
  3615.     lineNum++;
  3616.     }
  3617.     return(0);
  3618.  
  3619.  
  3620.  
  3621. /*
  3622.  *----------------------------------------------------------------------
  3623.  *
  3624.  * CltToMigd --
  3625.  *
  3626.  *    Return the migd pointer corresponding to a host, given its
  3627.  *    cltPtr.  This combines all the sanity checks in a single
  3628.  *    location.
  3629.  *
  3630.  * Results:
  3631.  *    A pointer to the internal Migd_Info record for the host is returned,
  3632.  *    or NULL if the entry doesn't exist.
  3633.  *
  3634.  * Side effects:
  3635.  *    None.
  3636.  *
  3637.  *----------------------------------------------------------------------
  3638.  */
  3639.  
  3640. static Migd_Info *
  3641. CltToMigd(cltPtr)
  3642.     Migd_OpenStreamInfo *cltPtr;
  3643. {
  3644.     Migd_Info *migdPtr;
  3645.  
  3646.     migdPtr = migInfoArray[cltPtr->host];
  3647.     if (migdPtr == (Migd_Info *) NULL) {
  3648.     return((Migd_Info *) NULL);
  3649.     }
  3650.     if (migdPtr->cltPtr != cltPtr) {
  3651.     SYSLOG1(LOG_WARNING,
  3652.            "Mismatch in client information for host %d.\n", cltPtr->host);
  3653.     return((Migd_Info *) NULL);
  3654.     }
  3655.     return(migdPtr);
  3656. }
  3657.  
  3658.  
  3659.  
  3660. /*
  3661.  *----------------------------------------------------------------------
  3662.  *
  3663.  * HostIsIdle --
  3664.  *
  3665.  *    Return whether a host is considered to be at least partly
  3666.  *    idle.  This should be changed to a macro once debugging is over.
  3667.  *
  3668.  * Results:
  3669.  *    A non-zero value is returned if the host referenced by migdPtr
  3670.  *    is considered to be idle, else 0.
  3671.  *
  3672.  * Side effects:
  3673.  *    None.
  3674.  *
  3675.  *----------------------------------------------------------------------
  3676.  */
  3677.  
  3678. static int
  3679. HostIsIdle(migdPtr)
  3680.     Migd_Info *migdPtr;
  3681. {
  3682.     if (global_Debug > 3) {
  3683.     PRINT_PID;
  3684.     fprintf(stderr, "HostIsIdle: %s was ", migdPtr->name);
  3685.     }
  3686.     if (migdPtr->info.state == MIG_HOST_IDLE ||
  3687.     migdPtr->info.state == MIG_HOST_PART_USED) {
  3688.     if (global_Debug > 3) {
  3689.         PRINT_PID;
  3690.         fprintf(stderr, "idle\n");
  3691.     }
  3692.     return(1);
  3693.     }
  3694.     if (global_Debug > 3) {
  3695.     PRINT_PID;
  3696.     fprintf(stderr, "not idle\n");
  3697.     }
  3698.     return(0);
  3699. }
  3700.  
  3701.  
  3702. /*
  3703.  *----------------------------------------------------------------------
  3704.  *
  3705.  * ForceHostIdle --
  3706.  *
  3707.  *    Restore sanity to a host by removing all indications of clients
  3708.  *    associated with the host and then putting it back on the idle list.
  3709.  *    This is necessary if, for example, someone requests a host
  3710.  *    and then doesn't release it.
  3711.  *
  3712.  * Results:
  3713.  *    None.
  3714.  *
  3715.  * Side effects:
  3716.  *    Host is put on idle list.
  3717.  *
  3718.  *----------------------------------------------------------------------
  3719.  */
  3720.  
  3721. static void
  3722. ForceHostIdle(migdPtr)
  3723.     Migd_Info *migdPtr;
  3724. {
  3725.     List_Links *listPtr;
  3726.     RequestInfo *reqPtr;
  3727.  
  3728.     if (global_Debug > 1) {
  3729.     PRINT_PID;
  3730.     fprintf(stderr, "ForceHostIdle: %s now believed to be idle.\n",
  3731.            migdPtr->name);
  3732.     }
  3733.     while (!List_IsEmpty(&migdPtr->clientList)) {
  3734.     listPtr = List_First(&migdPtr->clientList);
  3735.     List_Remove(listPtr);
  3736.     reqPtr = NEXT_HOST_REQUEST_TO_INFO(listPtr);
  3737.     if (global_Debug > 1) {
  3738.         PRINT_PID;
  3739.         fprintf(stderr, "Removing request from process %x.\n",
  3740.            (reqPtr->flags & MIG_PROC_AGENT) ? 
  3741.            reqPtr->client.processID : 
  3742.            reqPtr->client.cltPtr->processID);
  3743.     }
  3744.     /*
  3745.      * This is like an eviction, except no processes are getting evicted
  3746.      * -- we don't even think there are any there.  Instead, we notify
  3747.      * the client that we've revoked its permission to use this host
  3748.      * later on.
  3749.      */
  3750.     RevokePermission(reqPtr, REVOKE_IDLE);
  3751.     free((char *) reqPtr);
  3752.     }
  3753.     migdPtr->flags &= ~(MIGD_CHECK_COUNT | MIGD_WAS_EMPTY);
  3754.     if (HostIsIdle(migdPtr)) {
  3755.     List_Remove((List_Links *) migdPtr);
  3756.     } 
  3757.     InsertIdle(migdPtr);
  3758. }
  3759.  
  3760. /*
  3761.  *----------------------------------------------------------------------
  3762.  *
  3763.  * Global_GetStats --
  3764.  *
  3765.  *    Return the statistics structure to a user process.
  3766.  *
  3767.  * Results:
  3768.  *    0 for success, or an errno indicating the error.
  3769.  *    The statistics, and the size of the buffer, are returned.
  3770.  *
  3771.  * Side effects:
  3772.  *    None.
  3773.  *
  3774.  *----------------------------------------------------------------------
  3775.  */
  3776.  
  3777. /* ARGSUSED */
  3778. int
  3779. Global_GetStats(cltPtr, command, inBuffer, inBufSize, outBuffer,
  3780.            outBufSizePtr)
  3781.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  3782.                    the request. */
  3783.     int command;        /* Ignored. */
  3784.     char *inBuffer;        /* Not used. */
  3785.     int inBufSize;        /* Not used. */
  3786.     char *outBuffer;        /* Buffer to place results. */
  3787.     int *outBufSizePtr;        /* Size of the output buffer. */
  3788. {
  3789.     if (global_Debug > 3) {
  3790.     PRINT_PID;
  3791.     fprintf(stderr, "Global_GetStats called.\n");
  3792.     }
  3793.  
  3794.     if (*outBufSizePtr != sizeof(Mig_Stats)) {
  3795.     if (global_Debug > 0) {
  3796.         SYSLOG3(LOG_WARNING,
  3797.            "Global_GetStats: bad output buffer size (%d, not %d) from process %x\n",
  3798.            *outBufSizePtr, sizeof(Mig_Stats), cltPtr->processID);
  3799.     }
  3800.     return(EINVAL);
  3801.     }
  3802.     bcopy((char *) &global_Stats, outBuffer, sizeof(Mig_Stats));
  3803.     return(0);
  3804. }
  3805.  
  3806. /*
  3807.  *----------------------------------------------------------------------
  3808.  *
  3809.  * Global_ResetStats --
  3810.  *
  3811.  *    Reinitialize the statistics structure to a user process.  This
  3812.  *    is just a stub that takes standard ioctl arguments and calls the
  3813.  *    internal routine.
  3814.  *
  3815.  * Results:
  3816.  *    0 indicates success.
  3817.  *
  3818.  * Side effects:
  3819.  *    Statistics are zeroed.
  3820.  *
  3821.  *----------------------------------------------------------------------
  3822.  */
  3823.  
  3824. /* ARGSUSED */
  3825. int
  3826. Global_ResetStats(cltPtr, command, inBuffer, inBufSize, outBuffer,
  3827.            outBufSizePtr)
  3828.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  3829.                    the request. */
  3830.     int command;        /* Ignored. */
  3831.     char *inBuffer;        /* Not used. */
  3832.     int inBufSize;        /* Not used. */
  3833.     char *outBuffer;        /* Buffer to place results. */
  3834.     int *outBufSizePtr;        /* Size of the output buffer. */
  3835. {
  3836.     if (global_Debug > 1) {
  3837.     PRINT_PID;
  3838.     fprintf(stderr, "Global_ResetStats called.\n");
  3839.     }
  3840.  
  3841.     InitStats();
  3842.  
  3843.     return(0);
  3844. }
  3845.  
  3846.  
  3847.  
  3848. /*
  3849.  *----------------------------------------------------------------------
  3850.  *
  3851.  * Global_SetParms --
  3852.  *
  3853.  *    Set the parameters used by all migration daemons.
  3854.  *
  3855.  * Results:
  3856.  *    0 for success, or an errno indicating the error.
  3857.  *
  3858.  * Side effects:
  3859.  *    Host-specific daemon connections are made readable so
  3860.  *    they know to perform an ioctl to get the info.
  3861.  *
  3862.  *----------------------------------------------------------------------
  3863.  */
  3864.  
  3865. /* ARGSUSED */
  3866. int
  3867. Global_SetParms(cltPtr, command, inBuffer, inBufSize, outBuffer,
  3868.            outBufSizePtr)
  3869.     Migd_OpenStreamInfo *cltPtr;/* Information about the client making
  3870.                    the request. */
  3871.     int command;        /* Ignored. */
  3872.     char *inBuffer;        /* Buffer to get arguments from. */
  3873.     int inBufSize;        /* Size of the input buffer. */
  3874.     char *outBuffer;        /* Buffer to place results, not used. */
  3875.     int *outBufSizePtr;        /* Size of the output buffer, set to 0. */
  3876. {
  3877.     if (global_Debug > 1) {
  3878.     PRINT_PID;
  3879.     fprintf(stderr, "Global_SetParms called.\n");
  3880.     }
  3881.  
  3882.     /*
  3883.      * XXX need to add this here.
  3884.      */
  3885.     return(EINVAL);
  3886. }
  3887.     
  3888.  
  3889. /*
  3890.  *----------------------------------------------------------------------
  3891.  *
  3892.  * Global_DumpIdleList --
  3893.  *
  3894.  *    For debugging purposes: print an idle list, given the header.
  3895.  *
  3896.  * Results:
  3897.  *    None.
  3898.  *
  3899.  * Side effects:
  3900.  *    None.
  3901.  *
  3902.  *----------------------------------------------------------------------
  3903.  */
  3904.  
  3905. void
  3906. Global_DumpIdleList(hdrPtr)
  3907.     List_Links *hdrPtr;
  3908. {
  3909.     List_Links *itemPtr;
  3910.     Migd_Info  *migdPtr;
  3911.  
  3912.     LIST_FORALL(hdrPtr, itemPtr) {
  3913.     migdPtr = (Migd_Info *) itemPtr;
  3914.     fprintf(stderr, "\t%s idle %d seconds\n", migdPtr->name,
  3915.         migdPtr->info.loadVec.noInput);
  3916.     }
  3917.     fflush(stderr);
  3918. }
  3919.  
  3920.  
  3921. @
  3922.  
  3923.  
  3924. 2.4
  3925. log
  3926. @use multiple waiting lists, 1 per priority level
  3927. @
  3928. text
  3929. @d47 1
  3930. a47 1
  3931. static char rcsid[] = "$Header: /sprite/src/daemons/migd/RCS/global.c,v 2.3 90/09/14 14:05:45 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  3932. d2356 1
  3933. @
  3934.  
  3935.  
  3936. 2.3
  3937. log
  3938. @a few changes to fix bugs and to log instantiations of migd in a separate log 
  3939. file.
  3940. @
  3941. text
  3942. @d47 1
  3943. a47 1
  3944. static char rcsid[] = "$Header: /sprite/src/daemons/migd/RCS/global.c,v 2.2 90/07/05 18:35:27 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  3945. d152 2
  3946. a153 1
  3947. static List_Links *waitingLists;     /* array of lists of waiting clients,
  3948. d356 2
  3949. d361 1
  3950. a363 4
  3951.     waitingLists = (List_Links *) Malloc(maxArchTypes * sizeof(List_Links));
  3952.     for (j = 0; j < maxArchTypes; j++) {
  3953.     List_Init(&waitingLists[j]);
  3954.     }
  3955. d1027 1
  3956. a1027 1
  3957.     List_Links *waitingList = &waitingLists[archType];
  3958. d1635 3
  3959. a1637 2
  3960.  *    processes waiting for available hosts and let them ask again.
  3961.  *    Wakes up only processes of a particular archType.
  3962. d1652 1
  3963. a1652 1
  3964.     List_Links *waitingList = &waitingLists[archType];
  3965. d1658 2
  3966. d1668 33
  3967. a1700 16
  3968.     while (!List_IsEmpty(waitingList)) {
  3969.     /*
  3970.      * For each process waiting, get rid of the info saying it's waiting
  3971.      * and instead add a message to the process.
  3972.      */
  3973.     listPtr = List_First(waitingList);
  3974.     waitPtr = (Migd_WaitList *) listPtr;
  3975.     List_Remove(listPtr);
  3976.     cltPtr = waitPtr->cltPtr;
  3977.     cltPtr->waitPtr = (Migd_WaitList *) NULL;
  3978.     if (cltPtr->stoleTime > curTime - MIGD_STOLE_WINDOW) {
  3979.         if (global_Debug > 0) {
  3980.         PRINT_PID;
  3981.         fprintf(stderr,
  3982.                "\t** not telling process %x about host available, since we stole from it recently.\n",
  3983.                cltPtr->processID);
  3984. a1701 8
  3985.     } else {
  3986.         TellClient(cltPtr, 0);
  3987.         if (global_Debug > 0) {
  3988.         PRINT_PID;
  3989.         fprintf(stderr,
  3990.                "\t** telling process %x about host available.\n",
  3991.                cltPtr->processID);
  3992.         }
  3993. a1702 1
  3994.     free((char *) waitPtr);
  3995. a1703 1
  3996.     
  3997. @
  3998.  
  3999.  
  4000. 2.2
  4001. log
  4002. @increment stats for reclaimed hosts
  4003. @
  4004. text
  4005. @d47 1
  4006. a47 1
  4007. static char rcsid[] = "$Header: /sprite/src/daemons/migd/RCS/global.c,v 2.1 90/07/05 13:19:25 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  4008. d182 4
  4009. d245 1
  4010. d308 16
  4011. d942 1
  4012. d1202 1
  4013. a1202 1
  4014.     if (global_Debug > 2) {
  4015. d1205 2
  4016. a1206 2
  4017.            "CheckFairness evicting processes on host %d.\n",
  4018.             bestReqPtr->migdPtr->info.hostID);
  4019. d1212 1
  4020. a1212 1
  4021.         List_Remove(bestReqPtr->migdPtr);
  4022. d1761 1
  4023. a1761 15
  4024.     if (!(reqPtr->flags & MIG_PROC_AGENT)) {
  4025.         RevokePermission(reqPtr, REVOKE_EVICT);
  4026.     } else {
  4027.         /*
  4028.          * Request was on behalf of another process, so we don't
  4029.          * increment the client numEvicted field and instead add it
  4030.          * in to the totals independently.  (For regular clients we
  4031.          * accumulate multiple evictions/client and then the "squared"
  4032.          * statistic weights clustered evictions.)
  4033.          */
  4034.         if (migd_DoStats) {
  4035.         global_Stats.archStats[migdPtr->archType].counters.evicted++;
  4036.         global_Stats.archStats[migdPtr->archType].squared.evicted++;
  4037.         }
  4038.     }
  4039. d1863 8
  4040. d1897 12
  4041. a1909 1
  4042.     List_Remove(&reqPtr->nextInUse);
  4043. d2700 18
  4044. a2717 6
  4045.         migdPtr->info.state == MIG_HOST_PART_USED) &&
  4046.            oldForeign > 0 && vecPtr->foreignProcs == 0) {
  4047.     if (global_Debug > 1) {
  4048.         PRINT_PID;
  4049.         fprintf(stderr, "\t--%s now has no foreigners--\n",
  4050.            migdPtr->name);
  4051. a2718 1
  4052.     ForceHostIdle(migdPtr);
  4053. @
  4054.  
  4055.  
  4056. 2.1
  4057. log
  4058. @added fairness considerations, and moved around some code.
  4059. @
  4060. text
  4061. @d47 1
  4062. a47 1
  4063. static char rcsid[] = "$Header: /sprite/src/daemons/migd/RCS/global.c,v 2.0 90/06/30 17:06:57 douglis Stable Locker: douglis $ SPRITE (Berkeley)";
  4064. d1458 3
  4065. d1868 12
  4066. @
  4067.  
  4068.  
  4069. 2.0
  4070. log
  4071. @Changing version numbers.
  4072. @
  4073. text
  4074. @d47 1
  4075. a47 1
  4076. static char rcsid[] = "$Header: /sprite/src/daemons/migd/RCS/global.c,v 1.14 90/06/30 17:06:07 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  4077. d78 1
  4078. a78 1
  4079.  * clients.
  4080. d82 1
  4081. a82 1
  4082.     int hostID;            /* Host to tell client about. */
  4083. d96 2
  4084. d116 20
  4085. d149 3
  4086. d204 3
  4087. d332 2
  4088. d336 1
  4089. d629 1
  4090. a629 1
  4091.     Mig_InfoRequest *requestPtr;/* Request from client. */
  4092. d654 3
  4093. a656 3
  4094.     requestPtr = (Mig_InfoRequest *) inBuffer;
  4095.     firstHost = requestPtr->firstHost;
  4096.     numRecs = requestPtr->numRecs;
  4097. d741 1
  4098. a741 1
  4099.     Mig_IdleRequest *requestPtr;/* Request from client. */
  4100. d761 1
  4101. d771 2
  4102. a772 2
  4103.     requestPtr = (Mig_IdleRequest *) inBuffer;
  4104.     numHosts = requestPtr->numHosts;
  4105. d795 1
  4106. a795 1
  4107.     priority = requestPtr->priority;
  4108. d838 2
  4109. d841 2
  4110. a842 2
  4111.     tryPrio = MIG_LOW_PRIORITY;
  4112.     outPtr = (int *) (outBuffer + sizeof(int));
  4113. d844 8
  4114. a851 14
  4115.     while (total < numHosts && tryPrio <= priority) {
  4116.     idleList = &idleHostsArray[tryPrio][archType];
  4117.     nextPtr = List_First(idleList);
  4118.     while (total < numHosts && !List_IsAtEnd(idleList, nextPtr)) {
  4119.         listPtr = nextPtr;
  4120.         nextPtr = List_Next(nextPtr);
  4121.         migdPtr = (Migd_Info *) listPtr;
  4122.         if (global_Debug > 3) {
  4123.         PRINT_PID;
  4124.         fprintf(stderr, "Examining %s.\n",
  4125.                migdPtr->name);
  4126.         }
  4127.         if (migdPtr->info.hostID == requestPtr->virtHost ||
  4128.         migdPtr->info.hostID == cltPtr->host) {
  4129. d854 21
  4130. a874 2
  4131.             fprintf(stderr, "Skipping over %s.\n",
  4132.                migdPtr->name);
  4133. d876 19
  4134. a894 9
  4135.         continue;
  4136.         }
  4137.         if (migdPtr->info.migVersion != migVersion) {
  4138.         if (global_Debug > 3) {
  4139.             PRINT_PID;
  4140.             fprintf(stderr,
  4141.                "Migration version mismatch: %s version %d, %s version %d.\n",
  4142.                migdPtr->name, migdPtr->info.migVersion,
  4143.                reqMigdPtr->name, migVersion);
  4144. a895 5
  4145.         continue;
  4146.         }
  4147.         infoPtr = (Mig_Info *) &migdPtr->info;
  4148.         infoPtr->foreign[priority]++;
  4149.         if (infoPtr->foreign[priority] >= infoPtr->maxProcs) {
  4150. d897 8
  4151. a904 3
  4152.          * Used up all the processors on this host for processes
  4153.          * of this type, so put the host on the queue for
  4154.          * the next higher priority.
  4155. d906 11
  4156. a916 7
  4157.         List_Remove(listPtr);
  4158.         hostCounts[archType][infoPtr->state]--;
  4159.         if (priority < MIG_HIGH_PRIORITY) {
  4160.             List_Insert(listPtr,
  4161.                 LIST_ATREAR(&idleHostsArray
  4162.                         [priority + 1][archType]));
  4163.             infoPtr->state = MIG_HOST_PART_USED;
  4164. d918 2
  4165. a919 1
  4166.             infoPtr->state = MIG_HOST_FULL;
  4167. d921 28
  4168. a948 29
  4169.         hostCounts[archType][infoPtr->state]++;
  4170.         }
  4171.         /*
  4172.          * Allocate a new request info structure and set it up
  4173.          * so we can find this request via the host's record or via the
  4174.          * client process.  Only chain it to the client process if
  4175.          * it isn't an "agent" request, since we reclaim hosts on the
  4176.          * client's chain of requests when the connection is closed.
  4177.          *
  4178.          * XXX We'd like to assign multiple processors in a single shot
  4179.          * here...
  4180.          */
  4181.         reqPtr = mnew(RequestInfo);
  4182.         reqPtr->priority = priority;
  4183.         reqPtr->migdPtr = migdPtr;
  4184.         reqPtr->flags = requestPtr->flags;
  4185.         reqPtr->idleTime = migdPtr->info.loadVec.noInput;
  4186.         reqPtr->numProcessors = 1;
  4187.         if (! (reqPtr->flags & MIG_PROC_AGENT)) {
  4188.         reqPtr->client.cltPtr = cltPtr;
  4189.         List_InitElement(&reqPtr->nextClientRequest);
  4190.         List_Insert(&reqPtr->nextClientRequest,
  4191.                 LIST_ATREAR(&cltPtr->currentRequests));
  4192.         } else {
  4193.         reqPtr->client.processID = cltPtr->processID;
  4194.         migdPtr->flags |= MIGD_CHECK_COUNT;
  4195.         }
  4196.         if (migd_DoStats) {
  4197.         int noInput;
  4198. d950 6
  4199. a955 15
  4200.         global_Stats.totalObtained++;
  4201.         noInput = (infoPtr->loadVec.noInput + 30) / 60 ;
  4202.         reqPtr->timestamp = time(0);
  4203.         reqPtr->idleTime = noInput;
  4204.         ADD_WITH_OVERFLOW(archPtr->counters.hostIdleObtained, noInput);
  4205.         ADD_WITH_OVERFLOW(archPtr->squared.hostIdleObtained,
  4206.                   noInput * noInput);
  4207.         /*
  4208.          * Is this host being assigned to the last host that was
  4209.          * using it?
  4210.          */
  4211.         if (migdPtr->lastHostAssigned == cltPtr->host) {
  4212.             if (global_Debug > 4) {
  4213.             PRINT_PID;
  4214.             fprintf(stderr, "\t** Repeat assignment:\n");
  4215. d957 1
  4216. a957 7
  4217.             global_Stats.numRepeatAssignments++;
  4218.         } else if (migdPtr->lastHostAssigned == -1) {
  4219.             if (global_Debug > 4) {
  4220.             PRINT_PID;
  4221.             fprintf(stderr, "\t** First assignment to host:\n");
  4222.             }
  4223.             global_Stats.numFirstAssignments++;
  4224. a958 1
  4225.         migdPtr->lastHostAssigned = cltPtr->host;
  4226. d960 3
  4227. a962 9
  4228.         if (cltPtr->host == lastRequestHost) {
  4229.             if (global_Debug > 4) {
  4230.             PRINT_PID;
  4231.             fprintf(stderr, "\t** Repeat requesting host:\n");
  4232.             }
  4233.             global_Stats.numRepeatRequests++;
  4234.         }
  4235.         lastRequestHost = cltPtr->host;
  4236.         }
  4237. d964 3
  4238. a966 3
  4239.         List_InitElement(&reqPtr->nextHostRequest);
  4240.         List_Insert(&reqPtr->nextHostRequest,
  4241.             LIST_ATREAR(&migdPtr->clientList));
  4242. d968 15
  4243. a982 8
  4244.         if (global_Debug > 2) {
  4245.         PRINT_PID;
  4246.         fprintf(stderr, "\t** Assigning %s to process %x.\n",
  4247.                migdPtr->name, cltPtr->processID);
  4248.         }
  4249.         total++;
  4250.         *outPtr = infoPtr->hostID;
  4251.         outPtr++;
  4252. d984 1
  4253. a984 1
  4254.     tryPrio++;
  4255. d996 8
  4256. d1019 156
  4257. a1174 1
  4258.     
  4259. d1176 1
  4260. a1176 2
  4261.      * XXX Would like to record some per-user summary info here for fairness
  4262.      * policy issues.  But record per-process in any case.
  4263. d1178 13
  4264. a1190 6
  4265.     
  4266.     cltPtr->numInUse += total;
  4267.     if (migd_DoStats) {
  4268.     cltPtr->numObtained += total;
  4269.     if (cltPtr->numInUse > cltPtr->maxObtained) {
  4270.         cltPtr->maxObtained = cltPtr->numInUse;
  4271. d1192 3
  4272. a1195 2
  4273.     
  4274.  
  4275. a1196 1
  4276.     
  4277. d1267 1
  4278. a1267 2
  4279.  *    If a specific host is specified and the host is not being used by
  4280.  *    the client, EINVAL is returned, else 0.
  4281. a1328 3
  4282.     if (host != MIG_ALL_HOSTS) {
  4283.         returnCode = EINVAL;
  4284.     }
  4285. d1361 2
  4286. d1409 1
  4287. a1409 1
  4288.         if (msgPtr->hostID == host || host == MIG_ALL_HOSTS) {
  4289. d1440 3
  4290. a1442 2
  4291.             "Global_Done: process %x had a max of %d requests, %d obtained.\n",
  4292.                cltPtr->processID, requests, obtained);
  4293. d1467 3
  4294. a1469 5
  4295.     /*
  4296.      * XXX Would have to modify per-user summary info here for fairness
  4297.      * policy issues.  
  4298.      */
  4299.  
  4300. d1631 1
  4301. d1639 1
  4302. d1650 15
  4303. a1664 6
  4304.     TellClient(cltPtr, 0);
  4305.     if (global_Debug > 0) {
  4306.         PRINT_PID;
  4307.         fprintf(stderr,
  4308.            "\t** telling process %x about host available.\n",
  4309.            cltPtr->processID);
  4310. d1737 1
  4311. a1737 7
  4312.         /*
  4313.          * Remove it from the user's list.
  4314.          */
  4315.         List_Remove((List_Links *) reqPtr);
  4316.         cltPtr = reqPtr->client.cltPtr;
  4317.         TellClient(cltPtr, migdPtr->info.hostID);
  4318.         cltPtr->numEvicted++;
  4319. d1802 1
  4320. a1802 1
  4321. TellClient(cltPtr, hostID)
  4322. d1804 1
  4323. a1804 1
  4324.     int hostID;             /* ID of host, or 0. */
  4325. d1808 6
  4326. d1816 1
  4327. a1816 1
  4328.     msgPtr->hostID = hostID;
  4329. d1827 47
  4330. d1935 1
  4331. a1935 1
  4332.     *intPtr = msgPtr->hostID;
  4333. d1938 6
  4334. d2024 1
  4335. a2024 1
  4336.     int hostID;
  4337. d2080 1
  4338. a2080 1
  4339.     int hostID;
  4340. d3563 7
  4341. a3569 5
  4342.     if (!(reqPtr->flags & MIG_PROC_AGENT)) {
  4343.         List_Remove((List_Links *) reqPtr);
  4344.         migdPtr->info.foreign[reqPtr->priority] -= reqPtr->numProcessors;
  4345.         TellClient(reqPtr->client.cltPtr, migdPtr->info.hostID);
  4346.     }
  4347. @
  4348.  
  4349.  
  4350. 1.14
  4351. log
  4352. @mostly simplifications & moving common code to subroutines.
  4353. @
  4354. text
  4355. @d47 1
  4356. a47 1
  4357. static char rcsid[] = "$Header: /sprite/src/daemons/migd/RCS/global.c,v 1.13 90/06/26 22:09:03 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  4358. @
  4359.  
  4360.  
  4361. 1.13
  4362. log
  4363. @handle case when eviction comes after change back to availability.
  4364. @
  4365. text
  4366. @d47 1
  4367. a47 1
  4368. static char rcsid[] = "$Header: /sprite/src/daemons/migd/RCS/global.c,v 1.12 90/05/28 17:06:38 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  4369. d165 15
  4370. a179 13
  4371. static void CreateMigdRecord();  /* allocate a Migd_Info record. */
  4372. static void RestoreCheckPoint(); /* restore checkpoint from file */
  4373. static void SaveCheckPoint();      /* save checkpoint to file */
  4374. static void CheckHostStatus();      /* check the status of a host after an
  4375.                     update */
  4376. static int  RemoveHost();      /* remove host from list of hosts */
  4377. static int  HostIsIdle();      /* check for host being idle */
  4378. static void InsertIdle();      /* add host to list of idle hosts */
  4379. static void WakeupWaiters();      /* wake up processes that want more hosts. */
  4380. static void RecordEvictions();      /* remove host from idle list and notify
  4381.                     clients of evictions */
  4382. static void ForceHostIdle();      /* make a host seem idle */
  4383. static Migd_Info *CltToMigd();     /* map from client info to migd record */
  4384. d1436 1
  4385. a1436 3
  4386.     msgPtr = mnew(MessageBlock);
  4387.     List_InitElement(&msgPtr->links);
  4388.     msgPtr->hostID = 0;
  4389. a1442 4
  4390.     if (List_IsEmpty(&cltPtr->messages)) {
  4391.         MigPdev_MakeReady(cltPtr->streamPtr, (ClientData) NULL);
  4392.     }
  4393.     List_Insert((List_Links *) msgPtr, LIST_ATREAR(&cltPtr->messages));
  4394. a1476 1
  4395.     MessageBlock *msgPtr;
  4396. a1517 3
  4397.         /*
  4398.          * XXX Remigrate outstanding processes here, someday.
  4399.          */
  4400. d1519 1
  4401. a1519 7
  4402.         msgPtr = mnew(MessageBlock);
  4403.         List_InitElement(&msgPtr->links);
  4404.         msgPtr->hostID = migdPtr->info.hostID;
  4405.         if (List_IsEmpty(&cltPtr->messages)) {
  4406.         MigPdev_MakeReady(cltPtr->streamPtr, (ClientData) NULL);
  4407.         }
  4408.         List_Insert((List_Links *) msgPtr, LIST_ATREAR(&cltPtr->messages));
  4409. d1564 35
  4410. d3290 1
  4411. @
  4412.  
  4413.  
  4414. 1.12
  4415. log
  4416. @stats changes, plus bug fix for reopening unclosed connection over and over.
  4417. @
  4418. text
  4419. @d47 1
  4420. a47 1
  4421. static char rcsid[] = "$Header: /sprite/src/daemons/migd/RCS/global.c,v 1.11 90/05/14 21:32:59 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  4422. d2366 15
  4423. @
  4424.  
  4425.  
  4426. 1.11
  4427. log
  4428. @bug fixes, including List_Remove bug resulting from state not being set
  4429. properly.
  4430. @
  4431. text
  4432. @d47 1
  4433. a47 1
  4434. static char rcsid[] = "$Header: /sprite/src/daemons/migd/RCS/global.c,v 1.10 90/05/03 11:17:32 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  4435. d793 1
  4436. d887 1
  4437. d903 7
  4438. a909 1
  4439.             archPtr->numRepeatAssignments++;
  4440. d918 1
  4441. a918 1
  4442.             archPtr->numRepeatRequests++;
  4443. a1980 2
  4444.     cltPtr->type = MIGD_DAEMON;
  4445.     cltPtr->defaultSelBits = FS_WRITE;
  4446. d2082 13
  4447. a2094 1
  4448.     migdPtr->info = *infoPtr;
  4449. d2106 1
  4450. d2108 2
  4451. a2113 9
  4452.     if (infoPtr->state == MIG_HOST_IDLE && !infoPtr->loadVec.allowMigration) {
  4453.     if (global_Debug > 0) {
  4454.         PRINT_PID;
  4455.         fprintf(stderr,
  4456.             "Host %s marked as idle but not allowing migration.\n",
  4457.             migdPtr->name);
  4458.     }
  4459.     migdPtr->info.state = MIG_HOST_REFUSES;
  4460.     }
  4461. d2116 1
  4462. a2116 1
  4463.     if (migdPtr->info.state == MIG_HOST_IDLE) {
  4464. a2185 6
  4465.     if (global_Debug > 1) {
  4466.     PRINT_PID;
  4467.     fprintf(stderr, "Global_HostDown(host=%d, closed=%d) called.\n",
  4468.            hostID, closed);
  4469.     }
  4470.  
  4471. d2194 6
  4472. d2650 7
  4473. a2663 6
  4474.     fprintf(file, "%% \tnumRepeatRequests %u\n",
  4475.         global_Stats.archStats[i].numRepeatRequests);
  4476.     fprintf(file, "%% \tnumRepeatAssignments %u\n",
  4477.         global_Stats.archStats[i].numRepeatAssignments);
  4478.     fprintf(file, "%% \tnumFirstAssignments %u\n",
  4479.         global_Stats.archStats[i].numFirstAssignments);
  4480. d2871 36
  4481. a2930 21
  4482.     READLINE;
  4483.     numScanned = sscanf(buffer, "%% \tnumRepeatRequests %u",
  4484.         &global_Stats.archStats[i].numRepeatRequests);
  4485.     if (numScanned != 1) {
  4486.         BAD_INPUT;
  4487.     }
  4488.  
  4489.     READLINE;
  4490.     numScanned = sscanf(buffer, "%% \tnumRepeatAssignments %u",
  4491.         &global_Stats.archStats[i].numRepeatAssignments);
  4492.     if (numScanned != 1) {
  4493.         BAD_INPUT;
  4494.     }
  4495.  
  4496.     READLINE;
  4497.     numScanned = sscanf(buffer, "%% \tnumFirstAssignments %u",
  4498.         &global_Stats.archStats[i].numFirstAssignments);
  4499.     if (numScanned != 1) {
  4500.         BAD_INPUT;
  4501.     }
  4502.  
  4503. @
  4504.  
  4505.  
  4506. 1.10
  4507. log
  4508. @added missing statistic to checkpoint file
  4509. @
  4510. text
  4511. @d47 1
  4512. a47 1
  4513. static char rcsid[] = "$Header: /sprite/src/daemons/migd/RCS/global.c,v 1.9 90/05/02 14:35:35 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  4514. d136 2
  4515. d478 1
  4516. d892 5
  4517. a896 1
  4518.         if (reqMigdPtr->lastHostAssigned == infoPtr->hostID) {
  4519. d903 10
  4520. a912 1
  4521.         reqMigdPtr->lastHostAssigned = infoPtr->hostID;
  4522. d1154 2
  4523. d1559 5
  4524. d1745 3
  4525. d2006 4
  4526. a2009 2
  4527.     fprintf(stderr, "Global_HostUp - %s boot %d version %d maxProcs %d\n",
  4528.            migdPtr->name, infoPtr->bootTime, infoPtr->migVersion,
  4529. d2039 1
  4530. a2039 1
  4531.         time.tv_sec - MIG_GLOBAL_UPDATE_INTERVAL) {
  4532. a2073 1
  4533.         oldCltPtr->type = MIGD_CLOSED;
  4534. d2100 1
  4535. a2100 1
  4536.     infoPtr->state = MIG_HOST_REFUSES;
  4537. d2104 1
  4538. a2104 1
  4539.     if (infoPtr->state == MIG_HOST_IDLE) {
  4540. d2193 5
  4541. d2337 10
  4542. a2346 1
  4543.     InsertIdle(migdPtr);
  4544. d2645 2
  4545. d2649 2
  4546. d2883 7
  4547. d2897 7
  4548. d3265 1
  4549. a3265 1
  4550.     if (global_Debug > 1) {
  4551. @
  4552.  
  4553.  
  4554. 1.9
  4555. log
  4556. @fixed problem with thinking process never denied a host if it eventually got
  4557. as many as it could use, even if earlier it was denied.
  4558. @
  4559. text
  4560. @d47 1
  4561. a47 1
  4562. static char rcsid[] = "$Header: /sprite/src/daemons/migd/RCS/global.c,v 1.8 90/05/02 12:30:46 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  4563. d2624 3
  4564. d2884 8
  4565. @
  4566.  
  4567.  
  4568. 1.8
  4569. log
  4570. @keep track of how many clients got as many hosts as they requested.
  4571. @
  4572. text
  4573. @d47 1
  4574. a47 1
  4575. static char rcsid[] = "$Header: /sprite/src/daemons/migd/RCS/global.c,v 1.7 90/04/27 00:59:05 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  4576. d937 1
  4577. d1202 1
  4578. a1202 1
  4579.         if (cltPtr->maxRequests == cltPtr->maxObtained) {
  4580. @
  4581.  
  4582.  
  4583. 1.7
  4584. log
  4585. @changes for statistics gathering.
  4586. @
  4587. text
  4588. @d47 1
  4589. a47 1
  4590. static char rcsid[] = "$Header: /sprite/src/daemons/migd/RCS/global.c,v 1.6 90/04/24 18:00:32 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  4591. d1004 2
  4592. a1005 2
  4593.     for (i = 0; i < numArgs; i++) {
  4594.     status = Global_Done(cltPtr, *hostPtr);
  4595. d1035 1
  4596. a1035 1
  4597. Global_Done(cltPtr, host)
  4598. d1038 2
  4599. d1158 1
  4600. a1158 1
  4601.     if (host == MIG_ALL_HOSTS) {
  4602. d1183 5
  4603. a1187 1
  4604.     if (migd_DoStats) {
  4605. d1201 3
  4606. d2601 2
  4607. d2827 7
  4608. d2887 1
  4609. a2887 1
  4610.         &global_Stats.archStats[i].counters.hostIdleObtained[MIG_COUNTER_HIGH],
  4611. @
  4612.  
  4613.  
  4614. 1.6
  4615. log
  4616. @intermediate checkpoint
  4617. @
  4618. text
  4619. @d47 1
  4620. a47 1
  4621. static char rcsid[] = "$Header: /sprite/src/daemons/migd/RCS/global.c,v 1.5 90/04/03 11:08:25 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  4622. d224 1
  4623. a224 1
  4624.     fprintf(stderr, "Global_Init - process %x version %d on host %s:\n",
  4625. d359 1
  4626. d724 1
  4627. d737 1
  4628. a771 2
  4629.     cltPtr->numRequested += numHosts;
  4630.  
  4631. d775 17
  4632. d880 19
  4633. d945 7
  4634. a951 1
  4635.     cltPtr->numAssigned += total;
  4636. d1056 1
  4637. d1122 1
  4638. a1122 1
  4639.     
  4640. d1143 9
  4641. d1181 26
  4642. a1206 4
  4643.     requests = max(cltPtr->maxRequests, MIG_MAX_HOSTS_DIST);
  4644.     obtained = max(cltPtr->maxObtained, MIG_MAX_HOSTS_DIST);
  4645.     global_Stats.archStats.requestDist[requests]++;
  4646.     global_Stats.archStats.obtainedDist[obtained]++;
  4647. d1222 1
  4648. a1222 1
  4649.     return(0);
  4650. d1447 1
  4651. d1457 13
  4652. d1498 25
  4653. d1844 4
  4654. a1847 1
  4655.         if (global_Debug > 3) {
  4656. d1849 1
  4657. a1849 1
  4658.         fprintf(stderr, "Host is now idle.\n");
  4659. a1857 1
  4660.         break;
  4661. d2044 1
  4662. a2044 1
  4663.      * of clock skew.
  4664. d2046 4
  4665. a2049 1
  4666.     migdPtr->info.loadVec.timestamp = time.tv_sec;
  4667. a2054 1
  4668.      * InsertIdle changes the counters automatically. 
  4669. d2064 4
  4670. a2067 3
  4671.     hostCounts[migdPtr->archType][MIG_HOST_DOWN]--;
  4672.     hostCounts[migdPtr->archType][infoPtr->state]++;
  4673.     } else if (infoPtr->state == MIG_HOST_IDLE) {
  4674. a2068 3
  4675.     } else {
  4676.     hostCounts[migdPtr->archType][MIG_HOST_DOWN]--;
  4677.     hostCounts[migdPtr->archType][infoPtr->state]++;
  4678. d2282 4
  4679. a2285 1
  4680.         fprintf(stderr, "\t>>%s is no longer idle<<\n", migdPtr->name);
  4681. a2286 1
  4682.     RecordEvictions(migdPtr);
  4683. a2399 1
  4684.         PRINT_PID;
  4685. d2447 1
  4686. a2447 1
  4687.     int i, j;
  4688. a2499 3
  4689.     fprintf(checkPoint, "%% Version %d HasStats %d last run on %s.\n",
  4690.         migd_Version, migd_DoStats, migd_HostName);
  4691.  
  4692. d2579 8
  4693. a2586 5
  4694.     fprintf(file, "%% firstRun %d\n", global_Stats.firstRun);
  4695.     fprintf(file, "%% restarts %d\n", global_Stats.restarts);
  4696.     fprintf(file, "%% intervals %d\n", global_Stats.intervals);
  4697.     fprintf(file, "%% maxArchs %d\n", global_Stats.maxArchs);
  4698.     fprintf(file, "%% getLoadRequests %d\n", global_Stats.getLoadRequests);
  4699. d2588 1
  4700. a2588 1
  4701.     fprintf(file, "%% arch %d %s\n",
  4702. d2590 1
  4703. a2590 1
  4704.     fprintf(file, "%% \tnumClients %d\n",
  4705. d2592 1
  4706. a2592 1
  4707.     fprintf(file, "%% \tnumRepeatAssignments %d\n",
  4708. d2594 2
  4709. d2597 1
  4710. a2597 1
  4711.     fprintf(file, "%% \trequested %d %d\n",
  4712. d2600 1
  4713. a2600 1
  4714.     fprintf(file, "%% \tobtained %d %d\n",
  4715. d2603 1
  4716. a2603 1
  4717.     fprintf(file, "%% \tevicted %d %d\n",
  4718. d2606 1
  4719. a2606 1
  4720.     fprintf(file, "%% \treclaimed %d %d\n",
  4721. d2609 1
  4722. a2609 1
  4723.     fprintf(file, "%% \ttimeUsed %d %d\n",
  4724. d2612 15
  4725. a2626 12
  4726.     fprintf(file, "%% \thostIdleObtained %d %d\n",
  4727.         global_Stats.archStats[i].counters.hostIdleObtained,
  4728.         global_Stats.archStats[i].squared.hostIdleObtained);
  4729.     fprintf(file, "%% \thostIdleEvicted %d %d\n",
  4730.         global_Stats.archStats[i].counters.hostIdleEvicted,
  4731.         global_Stats.archStats[i].squared.hostIdleEvicted);
  4732.     fprintf(file, "%% \tnonIdleTransitions %d %d\n",
  4733.         global_Stats.archStats[i].counters.nonIdleTransitions,
  4734.         global_Stats.archStats[i].squared.nonIdleTransitions);
  4735.     fprintf(file, "%% \tidleTimeWhenActive %d %d\n",
  4736.         global_Stats.archStats[i].counters.idleTimeWhenActive,
  4737.         global_Stats.archStats[i].squared.idleTimeWhenActive);
  4738. d2629 2
  4739. a2630 2
  4740.     for (j = 0; j < MIG_MAX_HOSTS_DIST; j++) {
  4741.         fprintf(file, "%d ",
  4742. d2636 2
  4743. a2637 2
  4744.     for (j = 0; j < MIG_MAX_HOSTS_DIST; j++) {
  4745.         fprintf(file, "%d ",
  4746. d2648 1
  4747. a2648 1
  4748.         fprintf(file, "%d %d ",
  4749. d2684 2
  4750. d2733 3
  4751. a2735 3
  4752.     numScanned = sscanf(buffer, "%% Version %d HasStats %d\n",
  4753.         &lastVersion, &didStats);
  4754.     if (numScanned != 2) {
  4755. d2738 2
  4756. a2739 1
  4757.     if (lastVersion != migd_Version) {
  4758. d2743 3
  4759. a2745 2
  4760.             "ReadStats: mismatch in migd versions: ours is %d but last writer\n\tof checkpoint was %d.\n",
  4761.             migd_Version, lastVersion); 
  4762. d2760 1
  4763. a2760 1
  4764.     numScanned = sscanf(buffer, "%% firstRun %d", &global_Stats.firstRun);
  4765. d2766 1
  4766. a2766 1
  4767.     numScanned = sscanf(buffer, "%% restarts %d", &global_Stats.restarts);
  4768. d2773 1
  4769. a2773 1
  4770.     numScanned = sscanf(buffer, "%% intervals %d", &global_Stats.intervals);
  4771. d2779 1
  4772. a2779 6
  4773.     numScanned = sscanf(buffer, "%% maxArchs %d", &maxArchs);
  4774.     if (numScanned != 1) {
  4775.     BAD_INPUT;
  4776.     }
  4777.     READLINE;
  4778.     numScanned = sscanf(buffer, "%% getLoadRequests %d", &getLoadRequests);
  4779. d2792 6
  4780. d2800 1
  4781. a2800 1
  4782.     numScanned = sscanf(buffer, "%% arch %d %s", &archNum, archName);
  4783. d2809 1
  4784. a2809 1
  4785.     numScanned = sscanf(buffer, "%% \tnumClients %d",
  4786. d2816 1
  4787. a2816 1
  4788.     numScanned = sscanf(buffer, "%% \tnumRepeatAssignments %d",
  4789. d2823 8
  4790. a2830 1
  4791.     numScanned = sscanf(buffer, "%% \trequested %d %d",
  4792. d2837 1
  4793. a2837 1
  4794.     numScanned = sscanf(buffer, "%% \tobtained %d %d",
  4795. d2844 1
  4796. a2844 1
  4797.     numScanned = sscanf(buffer, "%% \tevicted %d %d",
  4798. d2851 1
  4799. a2851 9
  4800.     numScanned = sscanf(buffer, "%% \treclaimed %d %d",
  4801.         &global_Stats.archStats[i].counters.reclaimed,
  4802.         &global_Stats.archStats[i].squared.reclaimed);
  4803.  
  4804.     if (numScanned != 2) {
  4805.         BAD_INPUT;
  4806.     }
  4807.     READLINE;
  4808.     numScanned = sscanf(buffer, "%% \treclaimed %d %d",
  4809. d2859 1
  4810. a2859 1
  4811.     numScanned = sscanf(buffer, "%% \ttimeUsed %d %d",
  4812. d2867 26
  4813. a2892 28
  4814.     numScanned = sscanf(buffer, "%% \thostIdleObtained %d %d",
  4815.         &global_Stats.archStats[i].counters.hostIdleObtained,
  4816.         &global_Stats.archStats[i].squared.hostIdleObtained);
  4817.  
  4818.     if (numScanned != 2) {
  4819.         BAD_INPUT;
  4820.     }
  4821.     READLINE;
  4822.     numScanned = sscanf(buffer, "%% \thostIdleEvicted %d %d",
  4823.         &global_Stats.archStats[i].counters.hostIdleEvicted,
  4824.         &global_Stats.archStats[i].squared.hostIdleEvicted);
  4825.  
  4826.     if (numScanned != 2) {
  4827.         BAD_INPUT;
  4828.     }
  4829.     READLINE;
  4830.     numScanned = sscanf(buffer, "%% \tnonIdleTransitions %d %d",
  4831.         &global_Stats.archStats[i].counters.nonIdleTransitions,
  4832.         &global_Stats.archStats[i].squared.nonIdleTransitions);
  4833.  
  4834.     if (numScanned != 2) {
  4835.         BAD_INPUT;
  4836.     }
  4837.     READLINE;
  4838.     numScanned = sscanf(buffer, "%% \tidleTimeWhenActive %d %d",
  4839.         &global_Stats.archStats[i].counters.idleTimeWhenActive,
  4840.         &global_Stats.archStats[i].squared.idleTimeWhenActive);
  4841.     if (numScanned != 2) {
  4842. d2910 2
  4843. a2911 2
  4844.     for (j = 0; j < MIG_MAX_HOSTS_DIST; j++) {
  4845.         numScanned = fscanf(file, "%d ",
  4846. d2945 2
  4847. a2946 2
  4848.     for (j = 0; j < MIG_MAX_HOSTS_DIST; j++) {
  4849.         numScanned = fscanf(file, "%d ",
  4850. d2981 1
  4851. a2981 1
  4852.         numScanned = fscanf(file, "%d %d ",
  4853. d3181 50
  4854. a3230 4
  4855.     /*
  4856.      * XXX need to add this here.
  4857.      */
  4858.     return(EINVAL);
  4859. d3232 1
  4860. a3232 1
  4861.     
  4862. @
  4863.  
  4864.  
  4865. 1.5
  4866. log
  4867. @initialize host state properly if not allowing migration at start.  print
  4868. time of each ckpt for debugging.
  4869. @
  4870. text
  4871. @d47 1
  4872. a47 1
  4873. static char rcsid[] = "$Header: /sprite/src/daemons/migd/RCS/global.c,v 1.4 90/03/14 12:49:38 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  4874. d85 28
  4875. d114 2
  4876. a115 1
  4877. static int maxArchTypes = 10;      /* number of elements in arrays per-type */
  4878. d130 9
  4879. d141 2
  4880. a142 1
  4881. static int hostsUp = 0;
  4882. d144 3
  4883. d155 3
  4884. d176 5
  4885. d224 2
  4886. a225 2
  4887.     fprintf(stderr, "Global_Init - process %x on host %s:\n",
  4888.         migd_Pid, migd_HostName);
  4889. d310 8
  4890. d319 2
  4891. a320 1
  4892.      * list downtimes for hosts that aren't currently up.
  4893. d324 1
  4894. a324 1
  4895.     period.seconds = MIG_TIMEOUT;
  4896. d337 39
  4897. d470 1
  4898. d616 1
  4899. d722 1
  4900. a722 1
  4901.     Migd_RequestInfo *reqPtr;    /* Pointer to info for a request. */
  4902. d769 2
  4903. d826 1
  4904. d835 1
  4905. d847 1
  4906. a847 1
  4907.         reqPtr = mnew(Migd_RequestInfo);
  4908. d907 2
  4909. a908 1
  4910.     cltPtr->numHostsUsed += total;
  4911. a913 1
  4912.  
  4913. d1003 1
  4914. a1003 1
  4915.     int numReturned;        /* Number of hosts returned. */
  4916. d1008 1
  4917. a1008 1
  4918.     Migd_RequestInfo *reqPtr;    /* Pointer to info for a request. */
  4919. d1010 3
  4920. d1042 4
  4921. a1045 1
  4922.     return((host != MIG_ALL_HOSTS) ? EINVAL : 0);
  4923. a1050 1
  4924.     numReturned = 0;
  4925. d1059 1
  4926. a1059 1
  4927.     reqPtr = (Migd_RequestInfo *) cltListPtr;
  4928. d1102 1
  4929. d1104 4
  4930. d1127 5
  4931. d1142 1
  4932. a1142 2
  4933.      * policy issues.  Would also like to send message to anyone waiting
  4934.      * for hosts to be freed up.
  4935. d1144 3
  4936. d1183 1
  4937. d1189 1
  4938. d1204 1
  4939. a1204 1
  4940.                migdPtr->name, migdPtr->info.loadVec.noInput, 
  4941. d1228 3
  4942. a1230 4
  4943.     migdPtr->info.state = MIG_HOST_IDLE;
  4944.  
  4945.     return;
  4946.     }
  4947. d1239 1
  4948. a1239 1
  4949.     migdPtr->info.state = MIG_HOST_PART_USED;
  4950. d1249 2
  4951. a1250 2
  4952.         migdPtr->info.state = MIG_HOST_FULL;
  4953.         return;
  4954. d1260 1
  4955. a1260 1
  4956.         return;
  4957. d1266 10
  4958. d1368 1
  4959. a1368 1
  4960.     Migd_RequestInfo *reqPtr;
  4961. d1375 1
  4962. a1375 1
  4963.     if (global_Debug > 1) {
  4964. d1385 1
  4965. a1385 1
  4966.     if (global_Debug > 2) {
  4967. d1387 2
  4968. a1388 1
  4969.         fprintf(stderr, "RecordEvictions: removing request from process %x.\n",
  4970. d1744 1
  4971. d1746 2
  4972. a1747 1
  4973.         
  4974. d1935 2
  4975. a1936 1
  4976.      * Add the host to appropriate queue.
  4977. d1946 3
  4978. a1948 2
  4979.     }
  4980.     if (infoPtr->state == MIG_HOST_IDLE) {
  4981. d1950 3
  4982. d2044 1
  4983. d2046 1
  4984. d2122 1
  4985. d2125 1
  4986. d2169 1
  4987. d2171 1
  4988. d2205 2
  4989. a2206 1
  4990.  *    The state of each host in the checkpoint is initialized.
  4991. d2220 1
  4992. d2234 10
  4993. d2288 4
  4994. a2291 1
  4995.     migdPtr->info.state = MIG_HOST_DOWN;
  4996. d2293 3
  4997. a2295 3
  4998.     if (global_Debug > 2) {
  4999.     PRINT_PID;
  5000.     fprintf(stderr, "\nRestoreCheckPoint - returning.\n");
  5001. d2330 1
  5002. a2330 1
  5003.     int i;
  5004. d2338 2
  5005. a2339 1
  5006.     fprintf(stderr, "SaveCheckPoint - %s", ctime(&t));
  5007. d2359 2
  5008. a2360 2
  5009.     SYSLOG3(LOG_ERR,
  5010.            "\tdescriptor inode <%d,%d> version %d (presumably another migd running elsewhere).\n",
  5011. d2383 7
  5012. a2389 1
  5013.     fprintf(checkPoint, "%% Daemon last run on %s.\n", migd_HostName);
  5014. d2444 446
  5015. d2992 1
  5016. a2992 1
  5017.     Migd_RequestInfo *reqPtr;
  5018. @
  5019.  
  5020.  
  5021. 1.4
  5022. log
  5023. @stat the lock file once at the beginning and compare from there.
  5024. @
  5025. text
  5026. @d47 1
  5027. a47 1
  5028. static char rcsid[] = "$Header: /sprite/src/daemons/migd/RCS/global.c,v 1.3 90/03/12 13:44:57 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  5029. d1980 2
  5030. a1981 1
  5031.     migdPtr->info.state = MIG_HOST_ACTIVE;
  5032. d2170 1
  5033. a2170 1
  5034.     struct timeval time;
  5035. d2175 1
  5036. d2177 1
  5037. a2177 1
  5038.     fprintf(stderr, "SaveCheckPoint -\n");
  5039. d2215 1
  5040. a2215 1
  5041.     status = gettimeofday(&time, (struct timezone *) NULL);
  5042. d2238 1
  5043. a2238 1
  5044.         migdPtr->info.loadVec.timestamp < time.tv_sec - MIG_TIMEOUT) {
  5045. d2243 1
  5046. a2243 1
  5047.                migdPtr->name, time.tv_sec,
  5048. @
  5049.  
  5050.  
  5051. 1.3
  5052. log
  5053. @print pid's before messages in global log file; print dates here and
  5054. there; open files in append mode; changed file names to be in admin
  5055. subdir.  [this is a recording. beep!]
  5056. @
  5057. text
  5058. @d47 1
  5059. a47 1
  5060. static char rcsid[] = "$Header: /sprite/src/daemons/migd/RCS/global.c,v 1.2 90/02/28 10:45:36 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  5061. d116 1
  5062. a117 1
  5063.  
  5064. d214 6
  5065. d1735 15
  5066. a1749 2
  5067.      */
  5068.     if (migdPtr->info.loadVec.timestamp <
  5069. a2171 1
  5070.     struct stat descAtts;
  5071. a2181 15
  5072.     if (migd_LogToFiles) {
  5073.         PRINT_PID;
  5074.         fprintf(stderr, "Exiting: unable to stat %s: %s.\n",
  5075.             migd_GlobalPdevName, strerror(errno));
  5076.     }
  5077.     exit(1);
  5078.     }
  5079.     if (MigPdev_Stat(&descAtts) < 0) {
  5080.     SYSLOG1(LOG_ERR, "Exiting: unable to stat pdev descriptor: %s.\n",
  5081.            strerror(errno));
  5082.     if (migd_LogToFiles) {
  5083.         PRINT_PID;
  5084.         fprintf(stderr, "Exiting: unable to stat pdev descriptor: %s.\n",
  5085.             strerror(errno));
  5086.     }
  5087. a2187 15
  5088.     if (migd_LogToFiles) {
  5089.         PRINT_PID;
  5090.         fprintf(stderr, "Exiting: unable to stat %s: %s.\n",
  5091.             MIGD_LOCK_FILE, strerror(errno));
  5092.     }
  5093.     exit(1);
  5094.     }
  5095.     if (fstat(lockDesc, &descAtts) < 0) {
  5096.     SYSLOG1(LOG_ERR, "Exiting: unable to stat lock descriptor: %s.\n",
  5097.            strerror(errno));
  5098.     if (migd_LogToFiles) {
  5099.         PRINT_PID;
  5100.         fprintf(stderr, "Exiting: unable to stat lock descriptor: %s.\n",
  5101.             strerror(errno));
  5102.     }
  5103. d2192 2
  5104. a2193 2
  5105.     SYSLOG3(LOG_ERR,
  5106.            "Exiting: mismatch statting files: name inode <%d,%d>, version %d\n",
  5107. d2196 1
  5108. a2196 1
  5109.            "\tdescriptor inode <%d,%d> version %d.\n",
  5110. a2197 8
  5111.     if (migd_LogToFiles) {
  5112.         PRINT_PID;
  5113.         fprintf(stderr,
  5114.             "Exiting: mismatch statting files: name inode <%d,%d>, version %d,\n\tdescriptor inode <%d,%d>, version %d.\n",
  5115.             nameAtts.st_ino, nameAtts.st_devServerID,
  5116.             nameAtts.st_version, descAtts.st_ino,
  5117.             descAtts.st_devServerID, descAtts.st_version);
  5118.     }
  5119. a2265 4
  5120.     if (migd_LogToFiles) {
  5121.         PRINT_PID;
  5122.         fprintf(stderr, "Error syncing checkpoint file to disk.\n");
  5123.     }
  5124. @
  5125.  
  5126.  
  5127. 1.2
  5128. log
  5129. @print msgs to both syslog & error log when appropriate.  various bug
  5130. fixes to handle host crashes & duplicate daemons, mostly.  use the global 
  5131. daemon's timestamp to avoid clock skew problems.  check to make sure the
  5132. master pdev hasn't changed inodes on us (meaning there's another daemon
  5133. around someplace).
  5134. @
  5135. text
  5136. @d47 1
  5137. a47 1
  5138. static char rcsid[] = "$Header: /sprite/src/daemons/migd/RCS/global.c,v 1.1 90/02/15 19:17:39 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  5139. d106 1
  5140. a106 1
  5141. #define MIGD_CHECKPOINT_FILE "/sprite/admin/migd.check"
  5142. d109 4
  5143. d115 1
  5144. d158 1
  5145. d160 2
  5146. d167 3
  5147. d173 4
  5148. a176 2
  5149.     fprintf(stderr, "Global_Init - process %x on host %s\n",
  5150.         getpid(), migd_HostName);
  5151. d193 22
  5152. d405 1
  5153. d413 1
  5154. d416 2
  5155. d498 1
  5156. d528 1
  5157. d546 1
  5158. d556 1
  5159. d633 5
  5160. a637 2
  5161.         SYSLOG0(LOG_WARNING,
  5162.            "Global_GetIdle: no daemon for requester's host.\n");
  5163. d643 1
  5164. d655 1
  5165. d686 1
  5166. d693 1
  5167. d701 1
  5168. d756 2
  5169. a757 1
  5170.         if (global_Debug > 1) {
  5171. d768 1
  5172. d781 2
  5173. a782 1
  5174.     if (global_Debug > 1) {
  5175. d902 1
  5176. a902 1
  5177.     if (global_Debug > 1) {
  5178. d904 1
  5179. d909 1
  5180. d923 2
  5181. a924 1
  5182.     if (global_Debug > 1) {
  5183. d973 4
  5184. a976 2
  5185.         } 
  5186.         InsertIdle(migdPtr);
  5187. d978 1
  5188. d1010 1
  5189. a1057 8
  5190.     if (!migdPtr->info.loadVec.allowMigration) {
  5191.     if (global_Debug > 0) {
  5192.         fprintf(stderr, "InsertIdle: %s not really available, so not doing anything.\n",
  5193.            migdPtr->name);
  5194.     }
  5195.     return;
  5196.     }
  5197.  
  5198. d1073 1
  5199. d1086 1
  5200. d1093 1
  5201. d1117 1
  5202. d1125 1
  5203. d1170 2
  5204. a1171 1
  5205.     if (global_Debug > 1) {
  5206. d1189 1
  5207. d1238 1
  5208. d1247 2
  5209. a1248 1
  5210.     if (global_Debug > 1) {
  5211. d1321 2
  5212. a1322 1
  5213.     if (global_Debug) {
  5214. d1336 1
  5215. d1438 1
  5216. d1444 1
  5217. d1453 1
  5218. d1462 1
  5219. d1491 1
  5220. d1544 1
  5221. d1571 1
  5222. d1584 1
  5223. d1592 1
  5224. d1599 1
  5225. d1650 1
  5226. d1654 6
  5227. d1712 1
  5228. d1720 21
  5229. d1743 1
  5230. d1751 1
  5231. d1761 1
  5232. a1775 5
  5233.     status = gettimeofday(&time, (struct timezone *) NULL);
  5234.     if (status == -1) {
  5235.     SYSLOG1(LOG_ERR, "Error in gettimeofday: %s", strerror(errno));
  5236.     exit(1);
  5237.     }
  5238. d1783 9
  5239. d1828 1
  5240. d1863 1
  5241. d1869 1
  5242. d1945 1
  5243. d1957 1
  5244. d1966 1
  5245. d2000 2
  5246. a2001 1
  5247.     if (global_Debug > 1) {
  5248. d2007 2
  5249. a2008 1
  5250.     if (global_Debug > 1) {
  5251. d2017 1
  5252. d2056 1
  5253. d2061 1
  5254. d2071 3
  5255. a2073 2
  5256.         if (global_Debug > 3) {
  5257.         fprintf(stderr, "RestoreCheckPoint - skipping line: %s",
  5258. d2083 1
  5259. d2090 1
  5260. d2098 1
  5261. d2104 1
  5262. d2113 1
  5263. d2155 2
  5264. a2156 1
  5265.     if (global_Debug > 2) {
  5266. d2160 1
  5267. d2165 1
  5268. d2175 1
  5269. d2181 21
  5270. d2203 7
  5271. a2209 7
  5272.     nameAtts.st_devServerID != descAtts.st_devServerID) {
  5273.     SYSLOG2(LOG_ERR,
  5274.            "Exiting: mismatch statting pdevs: name inode <%d,%d>,\n",
  5275.            nameAtts.st_ino, nameAtts.st_devServerID);
  5276.     SYSLOG2(LOG_ERR,
  5277.            "\tdescriptor inode <%d,%d>.\n",
  5278.            descAtts.st_ino, descAtts.st_devServerID);
  5279. d2211 1
  5280. d2213 1
  5281. a2213 1
  5282.             "Exiting: mismatch statting pdevs: name inode <%d,%d>,\n\tdescriptor inode <%d,%d>.\n",
  5283. d2215 2
  5284. a2216 1
  5285.             descAtts.st_ino, descAtts.st_devServerID);
  5286. d2222 1
  5287. d2238 1
  5288. a2238 1
  5289.     
  5290. d2258 1
  5291. d2266 1
  5292. d2270 1
  5293. d2281 1
  5294. a2281 1
  5295.     }
  5296. d2287 1
  5297. d2357 1
  5298. d2363 1
  5299. d2369 1
  5300. d2403 1
  5301. d2412 1
  5302. d2461 1
  5303. d2503 1
  5304. @
  5305.  
  5306.  
  5307. 1.1
  5308. log
  5309. @Initial revision
  5310. @
  5311. text
  5312. @d47 1
  5313. a47 1
  5314. static char rcsid[] = "$Header: /user2/douglis/pdev_mig/migd/RCS/global.c,v 2.4 90/02/14 11:45:17 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  5315. d64 1
  5316. d67 1
  5317. d189 1
  5318. a189 1
  5319.       (maxArchTypes + 1));
  5320. d265 1
  5321. a265 1
  5322.     syslog(LOG_ERR, "invalid host ID from Host_Next: %d.\n",
  5323. d275 1
  5324. a275 1
  5325.     syslog(LOG_WARNING,
  5326. d307 1
  5327. a307 1
  5328.     syslog(LOG_WARNING,
  5329. d376 3
  5330. d465 1
  5331. a465 1
  5332.         syslog(LOG_WARNING,
  5333. d477 6
  5334. a482 3
  5335.         syslog(LOG_WARNING,
  5336.            "Global_GetLoadInfo: bad firstHost argument (%d) or output  buffer size (%d) for %d records, from process %x\n",
  5337.            firstHost,*outBufSizePtr, numRecs, cltPtr->processID);
  5338. d577 1
  5339. a577 1
  5340.         syslog(LOG_WARNING,
  5341. d585 11
  5342. d598 2
  5343. a599 3
  5344.            "Global_GetIdle: request for %d hosts from process %x (virtually on %d, physically on %d)\n",
  5345.            numHosts, cltPtr->processID,
  5346.            requestPtr->virtHost, cltPtr->host);
  5347. a614 10
  5348.     reqMigdPtr = migInfoArray[cltPtr->host];
  5349.     if (reqMigdPtr == (Migd_Info *) NULL ||
  5350.     reqMigdPtr->info.state == MIG_HOST_DOWN) {
  5351.     if (global_Debug > 0) {
  5352.         syslog(LOG_WARNING,
  5353.            "Global_GetIdle: no daemon for requester's host.\n");
  5354.     }
  5355.     return(ENOTCONN);
  5356.     }
  5357.     
  5358. d789 1
  5359. a789 1
  5360.         syslog(LOG_WARNING,
  5361. d1265 1
  5362. a1265 1
  5363.         syslog(LOG_WARNING,
  5364. d1269 1
  5365. a1269 1
  5366.     return(GEN_INVALID_ARG);
  5367. d1277 1
  5368. a1277 1
  5369.     return(GEN_FAILURE);
  5370. d1331 1
  5371. a1331 1
  5372.         syslog(LOG_WARNING,
  5373. d1378 3
  5374. a1380 1
  5375.     syslog(LOG_ERR, "RemoveHost: bad value of hostID: %d\n", hostID);
  5376. d1386 4
  5377. a1389 2
  5378.         syslog(LOG_ERR, "RemoveHost: %s is up; not removing.\n",
  5379.            migdPtr->name);
  5380. d1427 1
  5381. a1427 1
  5382.     syslog(LOG_ERR, "Global_IsHostUp: bad value of hostID: %d\n", hostID);
  5383. d1484 1
  5384. a1484 1
  5385.         syslog(LOG_WARNING,
  5386. d1496 1
  5387. a1496 1
  5388.     syslog(LOG_ERR, "Global_ChangeState: never heard from this host?  Exiting.\n");
  5389. d1572 2
  5390. d1581 1
  5391. a1581 1
  5392.         syslog(LOG_WARNING,
  5393. d1585 1
  5394. a1585 1
  5395.     return(GEN_INVALID_ARG);
  5396. d1610 1
  5397. a1610 1
  5398.     syslog(LOG_ERR,
  5399. d1612 1
  5400. a1612 1
  5401.     return(GEN_INVALID_ARG);
  5402. d1622 1
  5403. a1622 1
  5404.         syslog(LOG_ERR, "No entry in host database for host %d.\n",
  5405. d1624 1
  5406. a1624 1
  5407.         return(GEN_INVALID_ARG);
  5408. d1637 1
  5409. d1639 15
  5410. a1653 5
  5411.         syslog(LOG_WARNING,
  5412.            "Already talking to a daemon on %s.  Rejecting open.\n",
  5413.            migdPtr->name);
  5414.         cltPtr->type = MIGD_NEW;
  5415.         return(DEV_BUSY);
  5416. d1655 2
  5417. a1656 2
  5418.         if (global_Debug > 0) {
  5419.         syslog(LOG_WARNING,
  5420. a1659 1
  5421.         oldCltPtr = migdPtr->cltPtr;
  5422. d1662 12
  5423. d1675 2
  5424. a1676 1
  5425.     migdPtr->info = *infoPtr;
  5426. d1821 2
  5427. d1828 1
  5428. a1828 1
  5429.     syslog(LOG_ERR, "Global_UpdateLoad: never heard from this host?  Exiting.\n");
  5430. d1866 14
  5431. d1928 1
  5432. d2000 4
  5433. a2003 1
  5434.  *    in a while.
  5435. d2025 2
  5436. d2031 41
  5437. d2074 1
  5438. a2074 1
  5439.     syslog(LOG_WARNING, "SaveCheckPoint - error writing checkpoint: %s.\n",
  5440. d2080 2
  5441. a2081 2
  5442.     syslog(LOG_ERR, "Error in gettimeofday: %s", strerror(errno));
  5443.     return;
  5444. d2093 1
  5445. a2093 1
  5446.         syslog(LOG_WARNING,
  5447. d2125 7
  5448. d2166 1
  5449. a2166 1
  5450.     syslog(LOG_WARNING,
  5451. @
  5452.